{"owner":"headroomlabs-ai","repo":"headroom","hasSkills":true,"totalSkillsCount":33,"totalTokensCount":26296,"categories":["marketplace","root-instruction","project-spec","anthropic-skill","copilot-instructions","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":[".claude-plugin/marketplace.json","llms.txt","wiki/api.md",".github/plugin/marketplace.json","headroom/evals/README.md",".github/copilot-instructions.md","plugins/headroom-oauth2/CHANGELOG.md","plugins/headroom-snip/README.md","wiki/ARCHITECTURE.md","plugins/headroom-oauth2/README.md","plugins/headroom-agent-hooks/README.md","plugins/headroom-oauth2/SPEC.md","plugins/headroom-snip/tsconfig.json","plugins/hermes/README.md","plugins/openclaw/README.md","plugins/openclaw/openclaw.plugin.json","plugins/openclaw/package-lock.json","plugins/openclaw/package.json","plugins/openclaw/tsconfig.json","plugins/opencode/README.md","plugins/opencode/package-lock.json","plugins/opencode/package.json","plugins/opencode/tsconfig.json","e2e/wrap/tools/README.md","e2e/wrap/tools/package-lock.json","e2e/wrap/tools/package.json","plugins/headroom-agent-hooks/.claude-plugin/plugin.json","plugins/headroom-agent-hooks/hooks/hooks.json","plugins/headroom-snip/.claude-plugin/plugin.json","plugins/headroom-snip/hooks/hooks.json","plugins/hermes/headroom_retrieve/plugin.yaml","plugins/openclaw/hook-shim/HOOK.md","plugins/headroom-agent-hooks/.github/plugin/plugin.json"],"skills":{".claude-plugin/marketplace.json":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    },\n    {\n      \"name\": \"headroom-snip\",\n      \"source\": \"./plugins/headroom-snip\",\n      \"description\": \"Claude Code mod: watch Headroom snip tokens off every request, with an animated band, a /headroom log and a running total.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"claude-code\",\n        \"tokens\",\n        \"compression\",\n        \"mod\"\n      ]\n    }\n  ]\n}\n","llms.txt":"# Headroom\n\n> Context optimization layer for LLM applications. Compress tool outputs, logs, files, and RAG chunks before they reach the model. Same answers, 60–95% fewer tokens. Library, proxy, and MCP server. Apache 2.0, local-first.\n\nHeadroom is shipped as a Python package (`headroom-ai`), a TypeScript package (`headroom-ai`), an OpenAI + Anthropic-compatible HTTP proxy (`headroom proxy`), and an MCP server (`headroom_compress`, `headroom_retrieve`, `headroom_stats` tools). All four modes use the same compression pipeline: per-content-type compressors (JSON, code, logs, diffs, text) feed into a Compress-Cache-Retrieve (CCR) store so compression stays reversible — the LLM can ask for the original whenever it wants.\n\nThe canonical, always-current documentation index lives at the docs site below. If you can fetch one URL, fetch that one; the entries here are a hand-curated subset.\n\n## Canonical docs (start here)\n\n- [Live llms.txt (full doc index)](https://docs.headroomlabs.ai/llms.txt): Auto-generated index of every doc page with descriptions.\n- [Live llms-full.txt (every doc page concatenated)](https://docs.headroomlabs.ai/llms-full.txt): One Markdown blob containing every doc page. Use when you can spend the tokens for full context.\n- [Docs site](https://docs.headroomlabs.ai/docs): Human-browsable docs with search.\n- [GitHub repo](https://github.com/headroomlabs-ai/headroom): Source, issues, releases.\n- [PyPI package](https://pypi.org/project/headroom-ai/): Python install.\n- [npm package](https://www.npmjs.com/package/headroom-ai): TypeScript install.\n\n## Install (copy-paste-runnable)\n\n- Python: `pip install headroom-ai` (add `[all]` for every optional extra)\n- TypeScript / Node: `npm install headroom-ai` (or `pnpm add headroom-ai`, `bun add headroom-ai`)\n- Docker local: `docker run --rm -p 127.0.0.1:8787:8787 ghcr.io/headroomlabs-ai/headroom:latest --host 0.0.0.0`\n- Run the proxy: `headroom proxy --port 8787` then point any client at `http://127.0.0.1:8787`\n- Wrap an agent in one command: `headroom wrap claude` (also: `codex`, `copilot`, `cursor`, `aider`, `opencode`, `cline`, `continue`, `goose`, `openhands`, `openclaw`, `vibe`, `omp`)\n\n## Entry points\n\n- [Quickstart](https://docs.headroomlabs.ai/docs/quickstart): 5-minute end-to-end (install → compress → call the model).\n- [Installation](https://docs.headroomlabs.ai/docs/installation): All install paths, extras, Docker tags, env vars.\n- [Proxy server](https://docs.headroomlabs.ai/docs/proxy): Run as a local HTTP proxy in front of OpenAI / Anthropic / Gemini.\n- [MCP server](https://docs.headroomlabs.ai/docs/mcp): `headroom_compress`, `headroom_retrieve`, `headroom_stats` for Claude Code / Cursor / any MCP host.\n- [API reference](https://docs.headroomlabs.ai/docs/api-reference): Python + TypeScript `compress()` API.\n\n## How it works\n\n- [How compression works](https://docs.headroomlabs.ai/docs/how-compression-works): Three-stage pipeline + automatic content routing.\n- [SmartCrusher](https://docs.headroomlabs.ai/docs/smart-crusher): Statistical JSON / array compression (70–90% on tool outputs).\n- [Code compression](https://docs.headroomlabs.ai/docs/code-compression): AST-aware via tree-sitter (preserves imports, signatures, types).\n- [Text & log compression](https://docs.headroomlabs.ai/docs/text-and-logs): Search results, build logs, diffs.\n- [CCR (reversible)](https://docs.headroomlabs.ai/docs/ccr): Compress-Cache-Retrieve — originals never deleted; LLM retrieves on demand.\n\n## SDK / framework integrations\n\n- [Anthropic SDK](https://docs.headroomlabs.ai/docs/anthropic-sdk): `withHeadroom(anthropic)` wrapper.\n- [OpenAI SDK](https://docs.headroomlabs.ai/docs/openai-sdk): `withHeadroom(openai)` wrapper.\n- [Vercel AI SDK](https://docs.headroomlabs.ai/docs/vercel-ai-sdk): Middleware + `withHeadroom()`.\n- [LangChain](https://docs.headroomlabs.ai/docs/langchain): Chat models, memory, retrievers, agents.\n- [Agno](https://docs.headroomlabs.ai/docs/agno): Model wrapping + observability hooks.\n- [Strands](https://docs.headroomlabs.ai/docs/strands): Model wrapping + hook-based tool output compression.\n- [LiteLLM](https://docs.headroomlabs.ai/docs/litellm): Single callback; works with all 100+ LiteLLM providers.\n\n## Memory & cross-agent state\n\n- [Persistent memory](https://docs.headroomlabs.ai/docs/memory): Per-project SQLite + HNSW vector store. No cross-project bleed (GH #462).\n- [SharedContext](https://docs.headroomlabs.ai/docs/shared-context): Compressed inter-agent context handoffs.\n- [Failure learning](https://docs.headroomlabs.ai/docs/failure-learning): Offline analysis writes corrections to `CLAUDE.local.md` (default, gitignored) or `CLAUDE.md` (shared) / `AGENTS.md` / `GEMINI.md`.\n\n## Operations\n\n- [Configuration](https://docs.headroomlabs.ai/docs/configuration): Env vars, config file, per-call overrides.\n- [Benchmarks](https://docs.headroomlabs.ai/docs/benchmarks): Token-savings numbers across content types.\n- [Troubleshooting](https://docs.headroomlabs.ai/docs/troubleshooting): Common failure modes and fixes.\n- [Limitations](https://docs.headroomlabs.ai/docs/limitations): What Headroom won't do well today.\n\n## Headroom for Teams\n\nFor teams and companies that want Headroom across every developer rather than one laptop: Headroom Enterprise adds more savings (tool search for every model, harness tuning, extra compressors), automatic model routing (open source has opt-in, rule-based routing), prompt-injection and risky-tool-call removal, SSO, managed or VPC deployment, an org-wide savings dashboard, and support. Companies that sign a 12-month Enterprise plan get the first 3 months free.\n\n- [Headroom for Teams](https://docs.headroomlabs.ai/docs/teams): Open source vs Enterprise, and the 3-months-free offer.\n- [Claim 3 months free](https://headroom-perks.vercel.app/?source=github&utm_source=llms-txt): Perk sign-up form. One perk per company.\n\n## Licensing\n\nApache 2.0. Use commercially, modify, redistribute. Data stays on the user's machine when running the library, proxy, or MCP server locally. An anonymous usage beacon is **on by default**: it reports compression ratios, counters, provider and model IDs, OS and architecture, and never prompts, completions, code or file paths. Turn it off with `HEADROOM_BEACON=off`, `DO_NOT_TRACK=1`, or `HEADROOM_OFFLINE=1`. See [Telemetry](https://github.com/headroomlabs-ai/headroom#telemetry).\n","wiki/api.md":"# API Reference\n\n## HeadroomClient\n\nThe main entry point for Headroom SDK.\n\n```python\nfrom headroom import HeadroomClient\nfrom openai import OpenAI\n\nclient = HeadroomClient(\n    original_client=OpenAI(),\n    default_mode=\"optimize\",\n)\n```\n\n### Constructor Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `original_client` | `OpenAI \\| Anthropic` | Required | The underlying LLM client |\n| `provider` | `Provider` | Required (no default) | Token counting provider — e.g. `OpenAIProvider()`, `AnthropicProvider()` |\n| `default_mode` | `str` | `\"audit\"` | Default mode: \"audit\", \"optimize\", \"off\" |\n| `store_url` | `str` | `None` | Storage URL for metrics |\n| `model_context_limits` | `dict[str, int]` | `None` | Override context limits for models |\n| `cache_optimizer` | `BaseCacheOptimizer` | `None` (auto-detect) | Custom cache optimizer |\n| `enable_cache_optimizer` | `bool` | `True` | Enable provider-specific cache optimization |\n| `enable_semantic_cache` | `bool` | `False` | Enable query-level semantic caching |\n| `config` | `HeadroomConfig` | `None` | Full config object; set `config.smart_crusher` / `config.cache_aligner` here to override compression/cache-alignment settings — there is no separate `smart_crusher_config`/`cache_aligner_config` constructor kwarg |\n\n### Methods\n\n#### `chat.completions.create(**kwargs)`\n\nCreate a chat completion with optional optimization.\n\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[...],\n    headroom_mode=\"optimize\",  # Override default mode\n)\n```\n\n**Additional Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `headroom_mode` | `str` | Override mode for this request |\n| `headroom_query` | `str` | Query for relevance scoring |\n\n#### `chat.completions.simulate(**kwargs)`\n\nPreview optimization without making an API call.\n\n```python\nplan = client.chat.completions.simulate(\n    model=\"gpt-4o\",\n    messages=[...],\n)\n\nprint(f\"Tokens before: {plan.tokens_before}\")\nprint(f\"Tokens after: {plan.tokens_after}\")\nprint(f\"Savings: {plan.savings_percent:.1f}%\")\n```\n\n**Returns:** `SimulationResult`\n\n---\n\n## Configuration Classes\n\n### SmartCrusherConfig\n\n```python\nfrom headroom import SmartCrusherConfig\n\nconfig = SmartCrusherConfig(\n    min_tokens_to_crush=200,\n    max_items_after_crush=50,\n    keep_first=3,\n    keep_last=2,\n    relevance_threshold=0.3,\n    anomaly_std_threshold=2.0,\n    preserve_errors=True,\n)\n```\n\n### CacheAlignerConfig\n\n```python\nfrom headroom import CacheAlignerConfig\n\nconfig = CacheAlignerConfig(\n    extract_dates=True,\n    normalize_whitespace=True,\n    stable_prefix_min_tokens=100,\n)\n```\n\n### RelevanceScorerConfig\n\n```python\nfrom headroom import RelevanceScorerConfig\n\nconfig = RelevanceScorerConfig(\n    scorer_type=\"bm25\",  # \"bm25\", \"embedding\", or \"hybrid\"\n    embedding_model=None,  # Model name for embedding scorer\n    hybrid_alpha=0.5,  # Weight for hybrid scoring\n)\n```\n\n---\n\n## Data Models\n\n### SimulationResult\n\nReturned by `simulate()`.\n\n```python\n@dataclass\nclass SimulationResult:\n    tokens_before: int\n    tokens_after: int\n    tokens_saved: int\n    savings_percent: float\n    transforms_applied: list[str]\n    waste_signals: WasteSignals\n```\n\n### RequestMetrics\n\nMetrics for a single request.\n\n```python\n@dataclass\nclass RequestMetrics:\n    request_id: str\n    timestamp: datetime\n    model: str\n    tokens_input_before: int\n    tokens_input_after: int\n    tokens_output: int\n    cost_before: float\n    cost_after: float\n    transforms_applied: list[str]\n```\n\n### WasteSignals\n\nDetected waste in the request.\n\n```python\n@dataclass\nclass WasteSignals:\n    json_bloat_tokens: int\n    html_noise_tokens: int\n    whitespace_tokens: int\n    dynamic_date_tokens: int\n    repetition_tokens: int\n```\n\n---\n\n## Providers\n\n### OpenAIProvider\n\n```python\nfrom headroom import OpenAIProvider\n\nprovider = OpenAIProvider()\n\n# Get token counter\ncounter = provider.get_token_counter(\"gpt-4o\")\ntokens = counter.count_text(\"Hello, world!\")\n\n# Get context limit\nlimit = provider.get_context_limit(\"gpt-4o\")  # 128000\n\n# Estimate cost\ncost = provider.estimate_cost(\n    input_tokens=1000,\n    output_tokens=500,\n    model=\"gpt-4o\",\n)\n```\n\n### AnthropicProvider\n\n```python\nfrom headroom import AnthropicProvider\nfrom anthropic import Anthropic\n\nprovider = AnthropicProvider(client=Anthropic())\n\ncounter = provider.get_token_counter(\"claude-3-5-sonnet-latest\")\ntokens = counter.count_messages(messages)  # Accurate count via API\n```\n\n---\n\n## Relevance Scoring\n\n### BM25Scorer\n\nFast keyword-based scoring (zero dependencies).\n\n```python\nfrom headroom import BM25Scorer\n\nscorer = BM25Scorer()\nscores = scorer.score_items(\n    items=[\"item 1\", \"item 2\", ...],\n    query=\"search query\",\n)\n```\n\n### EmbeddingScorer\n\nSemantic similarity scoring (requires `sentence-transformers`).\n\n```python\nfrom headroom import EmbeddingScorer, embedding_available\n\nif embedding_available():\n    scorer = EmbeddingScorer(model=\"all-MiniLM-L6-v2\")\n    scores = scorer.score_items(items, query)\n```\n\n### HybridScorer\n\nCombines BM25 and embeddings.\n\n```python\nfrom headroom import HybridScorer\n\nscorer = HybridScorer(alpha=0.5)  # 50% BM25, 50% embedding\nscores = scorer.score_items(items, query)\n```\n\n### create_scorer()\n\nFactory function to create scorers.\n\n```python\nfrom headroom import create_scorer\n\n# Auto-select best available scorer\nscorer = create_scorer()\n\n# Explicitly choose type\nscorer = create_scorer(scorer_type=\"hybrid\", alpha=0.7)\n```\n\n---\n\n## Transforms (Direct Use)\n\n### SmartCrusher\n\n```python\nfrom headroom import SmartCrusher\n\ncrusher = SmartCrusher()\nresult = crusher.crush(\n    data={\"results\": [...]},\n    query=\"user query\",\n)\n```\n\n### CacheAligner\n\n```python\nfrom headroom import CacheAligner\n\naligner = CacheAligner()\nresult = aligner.align(messages)\n```\n\n> **Context management** is handled automatically inside the pipeline\n> (live-zone-only compression). The position-based `RollingWindow` and\n> score-based `IntelligentContextManager` / `MessageScorer` APIs have been\n> removed and are no longer part of Headroom.\n\n### TransformPipeline\n\n```python\nfrom headroom import TransformPipeline\n\npipeline = TransformPipeline(\n    [\n        SmartCrusher(),\n        CacheAligner(),\n    ]\n)\n\nresult = pipeline.transform(messages)\n```\n\n---\n\n## Utilities\n\n### Tokenizer\n\n```python\nfrom headroom import Tokenizer, count_tokens_text, count_tokens_messages\n\n# Quick counting\ntokens = count_tokens_text(\"Hello, world!\", model=\"gpt-4o\")\n\n# With tokenizer instance\ntokenizer = Tokenizer(model=\"gpt-4o\")\ntokens = tokenizer.count_text(\"Hello\")\ntokens = tokenizer.count_messages(messages)\n```\n\n### generate_report()\n\nGenerate HTML/Markdown reports from stored metrics.\n\n```python\nfrom headroom import generate_report\n\nreport = generate_report(\n    store_url=\"sqlite:///headroom.db\",\n    format=\"html\",\n    period=\"day\",\n)\n```\n\n---\n\n## TypeScript SDK\n\nFor the TypeScript SDK API reference, see [TypeScript SDK](typescript-sdk.md).\n\nThe TypeScript SDK provides `compress()`, `HeadroomClient`, and framework adapters for Vercel AI SDK, OpenAI, and Anthropic.\n",".github/plugin/marketplace.json":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    }\n  ]\n}\n","headroom/evals/README.md":"# Headroom Evaluation Framework\n\n**Prove that compression preserves LLM accuracy through rigorous OSS benchmarks.**\n\n## Results\n\n### Standard Benchmarks — \"No Accuracy Loss\"\n\n| Benchmark | Category | N | Baseline | Headroom | Delta |\n|-----------|----------|---|----------|----------|-------|\n| [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |\n| [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |\n\n### Compression Benchmarks — \"Big Savings, Accuracy Preserved\"\n\n| Benchmark | Category | N | Accuracy | Compression | Method |\n|-----------|----------|---|----------|-------------|--------|\n| [SQuAD v2](https://huggingface.co/datasets/rajpurkar/squad_v2) | QA | 100 | **97%** | 19% | Before/After |\n| [BFCL](https://huggingface.co/datasets/gorilla-llm/Berkeley-Function-Calling-Leaderboard) | Tool/Function | 100 | **97%** | 32% | LLM-as-Judge |\n| Tool Outputs (built-in) | Agent | 8 | **100%** | 20% | Before/After + Proxy |\n| CCR Needle Retention | Lossless | 50 | **100%** | 77% | Exact Match |\n\nModel: `gpt-4o-mini` | Suite cost: ~$3 | Duration: ~15 min\n\n## Installation\n\n```bash\npip install \"headroom-ai[all]\"    # Everything including evals (recommended)\npip install \"headroom-ai[evals]\"  # Evaluation framework only\n```\n\n## Quick Start\n\n### Run the Evaluation Suite\n\n```bash\n# Quick smoke test (8 cases, ~10s)\npython -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n\n# Full Tier 1 suite (~$3, ~15 min) — requires proxy running\npython -m headroom.evals suite --tier 1 -o eval_results/\n\n# Extended suite (Tiers 1+2, ~$8, ~1 hr)\npython -m headroom.evals suite --tier 2 -o eval_results/\n\n# CI mode — exit 1 on any regression\npython -m headroom.evals suite --tier 1 --ci\n\n# List all available datasets\npython -m headroom.evals list\n```\n\n### Running with the Proxy (Recommended)\n\nFor the most accurate evaluation, run through the Headroom proxy which provides\nthe full stack: compression + CCR retrieval + cache alignment.\n\n```bash\n# Terminal 1: Start the proxy\nheadroom proxy --port 8787\n\n# Terminal 2: Run evals (auto-detects proxy)\npython -m headroom.evals suite --tier 1 -o eval_results/\n```\n\nWithout the proxy, the eval runner falls back to local compression only (no CCR).\n\n### Python API\n\n```python\nfrom headroom.evals.suite_runner import SuiteRunner\nfrom headroom.evals.reports.report_card import save_reports\n\n# Run Tier 1 suite\nrunner = SuiteRunner(model=\"gpt-4o-mini\", tiers=[1])\nresult = runner.run()\n\n# Save Markdown, JSON, and HTML reports\nsave_reports(result, \"eval_results/\")\n```\n\n## Session Probes (real recorded sessions)\n\nThe benchmark suites above prove the compressors in vitro. Session probes\nmeasure what compression removed from YOUR real sessions, offline and with no\nLLM or API key:\n\n```bash\n# 1. Record: run the proxy with recording enabled (opt-in; recordings contain\n#    full conversation content in plaintext and stay on this machine)\nHEADROOM_PROBE_RECORD_DIR=~/.headroom/probe-recordings headroom proxy start\n\n# 2. Use your agent through the proxy as normal, then score retention:\nheadroom evals probes --recordings ~/.headroom/probe-recordings\n```\n\nProbe targets are extracted from original tool results across three\ndimensions — exact numerics, artifact trail (paths/URLs/hashes), error\nevidence — and classified as retained (verbatim or surviving a format\nconversion), recoverable (behind a CCR retrieval marker), or lost. The report\nbuckets retention by compression ratio and groups it per transform. Use\n`--json-output report.json` for machine-readable results.\n\n## Evaluation Tiers\n\n### Tier 1: Core Report Card (~$3, ~15 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| GSM8K | lm-eval harness | Math reasoning accuracy |\n| TruthfulQA | lm-eval harness | Factual accuracy |\n| MMLU | lm-eval harness | 57-subject knowledge |\n| ARC-Challenge | lm-eval harness | Science reasoning |\n| HumanEval | lm-eval harness | Code generation |\n| SQuAD v2 | Before/After | Reading comprehension with compression |\n| BFCL | LLM-as-Judge | Function calling with compressed schemas |\n| Tool Outputs | Before/After + Proxy | Agent tool output compression |\n| CCR Needle Retention | Compression-only | Lossless anomaly preservation |\n\n### Tier 2: Extended (~$5 more, ~30 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HotpotQA | Before/After | Multi-hop QA with compressed passages |\n| MS MARCO | Before/After | RAG with compressed search results |\n| CodeSearchNet | Before/After | Code understanding after compression |\n| Info Retention | Compression-only | Probe fact survival in compressed output |\n\n### Tier 3: Deep Dive (~$9 more, ~45 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HellaSwag | lm-eval harness | Commonsense reasoning |\n| NarrativeQA | Before/After | Long narrative comprehension |\n| TriviaQA | Before/After | Factoid QA at scale |\n\n## Evaluation Methods\n\n### Before/After (Default)\n\nCompares LLM responses on original vs. compressed context:\n\n```\nOriginal Context ──► LLM ──► Response A\n                                         ├─► Compare (F1, semantic sim, GT match)\nCompressed Context ──► LLM ──► Response B\n```\n\nWhen the Headroom proxy is running, the \"compressed\" path goes through the full\nstack (compression + CCR tool injection + cache alignment), which is the real\nproduction experience.\n\n### LLM-as-Judge (for BFCL, tool use)\n\nUses an LLM judge to compare the compressed response against ground truth\nsemantically. This handles cases where the same correct answer can be expressed\nin different formats (function call JSON vs natural language computation).\n\n```\nCompressed Context ──► LLM ──► Response ──► LLM Judge ──► Score 1-5\n                                                  ▲\n                                          Ground Truth\n```\n\nScore >= 3 (\"partially correct or better\") = PASS. This means the compressed\ncontext preserved enough information for the LLM to reach the right answer.\n\n### Compression-Only (Zero Cost)\n\nTests compression quality without any LLM API calls:\n- **CCR Needle Retention**: Compress JSON arrays, verify errors/anomalies survive\n- **Information Retention**: Compress and check if probe facts are preserved\n\n## Available Datasets\n\n### RAG / Retrieval\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `hotpotqa` | Multi-hop QA over multiple Wikipedia passages | 100 |\n| `natural_questions` | Real Google search questions with Wikipedia answers | 100 |\n| `triviaqa` | Large-scale trivia QA with evidence documents | 100 |\n| `msmarco` | Real Bing search queries with relevant passages | 100 |\n| `squad` | SQuAD v2 reading comprehension | 100 |\n\n### Tool Use\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `bfcl` | Berkeley Function Calling Leaderboard | 100 |\n| `toolbench` | Real-world API tool usage scenarios | 100 |\n| `tool_outputs` | Built-in realistic tool outputs (JSON, logs, etc.) | 8 |\n\n### Long Context\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `longbench` | Long context understanding (4K-128K tokens) | 50 |\n| `narrativeqa` | Story comprehension | 100 |\n\n### Code\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `codesearchnet` | Code snippets with descriptions | 100 |\n| `humaneval` | Programming problems (OpenAI) | 164 |\n\n## Metrics\n\n| Metric | Description | Pass Threshold |\n|--------|-------------|----------------|\n| F1 Score | Token overlap between responses | > 0.7 |\n| Semantic Similarity | Embedding cosine similarity | > 0.85 |\n| Ground Truth Match | Answer present in response | True |\n| LLM Judge Score | 1-5 semantic correctness scale | >= 3 |\n| Accuracy Preserved | Any of the above passes | True |\n\n## CI/CD Integration\n\n```yaml\n# .github/workflows/eval.yml\nname: Evaluation Suite\n\non:\n  pull_request:\n    paths: ['headroom/transforms/**', 'headroom/evals/**']\n  schedule:\n    - cron: '0 6 * * 1'  # Weekly\n\njobs:\n  smoke-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with: { python-version: \"3.11\" }\n      - run: pip install -e \".[all]\"\n      - name: CCR Round-trip (zero cost)\n        run: |\n          python -c \"\n          from headroom.evals.runners.compression_only import CompressionOnlyRunner\n          r = CompressionOnlyRunner()\n          result = r.evaluate_ccr_lossless(r.generate_ccr_test_cases(50))\n          assert result.passed, f'CCR failures: {result.errors}'\n          print(f'CCR: {result.passed_cases}/{result.total_cases} PASS')\n          \"\n      - name: Quick eval\n        run: python -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n        env:\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n```\n\n## Environment Variables\n\nSet in `.env` at project root (auto-loaded by the suite runner):\n\n```\nOPENAI_API_KEY=sk-...      # Required for OpenAI models\nANTHROPIC_API_KEY=sk-ant-... # Required for Anthropic models\n```\n\n## Architecture\n\n```\nheadroom/evals/\n├── __init__.py              # Public API\n├── __main__.py              # CLI (quick, list, benchmark, suite, report)\n├── core.py                  # EvalCase, EvalResult, EvalSuite\n├── datasets.py              # 12 dataset loaders (HuggingFace + built-in)\n├── metrics.py               # F1, semantic similarity, ROUGE-L, BLEU\n├── cost_tracker.py          # API spend tracking + budget enforcement\n├── suite_runner.py          # Tiered suite orchestrator (16 benchmarks)\n├── comprehensive_benchmark.py  # EleutherAI lm-eval harness wrapper\n├── runners/\n│   ├── before_after.py      # Before/After + LLM-as-Judge + proxy support\n│   └── compression_only.py  # Zero-cost CCR + info retention evals\n├── reports/\n│   └── report_card.py       # Markdown, JSON, HTML report generation\n└── memory/\n    ├── judge.py             # LLM-as-judge (OpenAI, Anthropic, LiteLLM)\n    └── runner*.py           # Memory-specific evaluation\n```\n",".github/copilot-instructions.md":"When performing a pull request review in this repository:\r\n\r\n1. Treat `.github/PULL_REQUEST_TEMPLATE.md` and `CONTRIBUTING.md` as required policy, not optional guidance.\r\n2. Flag pull requests that do not include concrete \"Real Behavior Proof\" with environment, exact commands or steps, observed result, and what was not tested.\r\n3. Be strict about contributor verification: missing tests, missing runtime evidence, or placeholder PR text should be called out.\r\n4. For user-facing, release, dependency, workflow, or security-sensitive changes, prefer blocking feedback over optional suggestions.\r\n5. Focus on correctness, safety, and whether the PR is actually ready for human maintainer review.\r\n","plugins/headroom-oauth2/CHANGELOG.md":"# Changelog\n\n## 0.1.1\n\n- Inject the upstream bearer only on requests that go upstream. Local routes\n  (`/health`, `/stats*`, `/metrics`, `/v1/compress*`, `/ext/*`, …; see README)\n  are passed through untouched, so an unreachable IdP no longer 502s health\n  probes and management calls no longer mint tokens. `/p/<project>/` prefixes\n  are stripped first.\n- Startup log carries `scheme://host` of the token URL and the mint log a scope\n  count, instead of the full URL and scope list.\n- Requires `headroom-ai` ≥ 0.40 (extension middleware inside the proxy-token gate).\n\n## 0.1.0\n\nInitial release — generic OAuth2 client-credentials upstream-auth extension for the Headroom proxy.\n\n- Mints an OAuth2 client-credentials (RFC 6749 §4.4) bearer from a configurable token endpoint and\n  injects it as the upstream `Authorization` on each proxied request, via Headroom's opt-in\n  `headroom.proxy_extension` seam (`--proxy-extension oauth2`). No core changes; vendor-neutral.\n- `post` and `basic` client-auth styles; scopes, `audience`, RFC 8707 `resource`, static upstream\n  headers, configurable timeout/skew — all env-driven.\n- Token caching with single-flight refresh and pre-expiry skew; `expires_in` clamped to a positive\n  TTL.\n- Fails closed on misconfiguration; returns `502 upstream_auth_error` on mint failure without\n  leaking the IdP error body. `token_url` https-enforced (loopback exempt). Std-lib only (system\n  cert store -> works behind corporate SSL inspection).\n","plugins/headroom-snip/README.md":"# headroom-snip\n\nA Claude Code mod that shows what Headroom does to each request, live. When a\nrequest goes through the proxy, a pair of scissors runs along a bar the size of\nthe original prompt, cuts it down to what was actually sent, and the token\ncount drops as it goes:\n\n```\n✂ headroom 21k → 16k   tok ━━━━━━━━━━━━━━━━━━━━━━━✂⡀⠄⠂⠁⢀⠈⠐⠠ −81%\n✂ headroom 21k → 7.6k  tok ━━━━━━━━━━━✂⠈⠐⠠⡀⠄⠂⠁⢀⠈⠐⠠⡀⠄⠂······ −81%\n✂ headroom 21k → 4.1k  tok ━━━━━━·························· −81%\n  JSON crush ×2 · Kompress text · cache align   project 184k saved (62%) over 23 req ≈ 307 pages  details  hide\n```\n\n## What it shows\n\n- **The band above the prompt.** The latest request: original → sent tokens,\n  the snip animation, and the percentage cut. Below that, which compressors did\n  the cutting (`JSON crush`, `code AST`, `Kompress text`, `log squash`,\n  `cache align`, ...) and the running total since the session started. A request sent unchanged says why,\n  for example `kept: user message, recent code` or `nothing worth a snip`.\n- **`/headroom`.** Opens a pane with the requests since the session started: one bar per\n  request, what was cut and what was protected, how long compression took, the\n  biggest snip so far, and an all-time total.\n  `/headroom hide` and `/headroom show` toggle the band.\n- **The status line.** `✂ 184k tok saved · 62%`.\n- **Milestone toasts** at 10k, 50k, 100k, 250k, 500k, 1M and 5M tokens saved.\n- **No proxy?** If nothing answers, the band says so and suggests\n  `headroom wrap claude`.\n\n## How it works\n\nWhile a turn runs, the mod polls the proxy's loopback `GET /stats?cached=1`\nonce a second. It reads the `recent_requests` tail (per-request token counts\nand `transforms_applied`), and keeps polling for a few seconds after the turn\nends. Requests stamped before the session started count as history: they\naren't animated or added to the totals, even if the proxy only comes up later.\nNothing leaves your machine.\n\nThe proxy can't tell Claude Code sessions apart, so the totals are never\nper session. What they cover depends on how Claude Code reaches the proxy:\n\n- **Through `headroom wrap claude`:** each request carries an\n  `X-Headroom-Project` header naming the launch directory (its basename, so\n  two directories with the same name share a tag). The mod counts every\n  request with this session's tag, including other sessions in the same\n  project, and leaves other projects out. The proxy only reports tags for its\n  last ten requests, so a request it can't attribute is left out rather than\n  guessed. The band says \"project\" and `/headroom` names the project.\n- **Any other way:** there is no tag, so the totals cover every client on the\n  proxy since this session started. The band says \"proxy\" and `/headroom` says\n  so.\n\nIt finds the proxy in this order:\n\n1. `HEADROOM_PROXY_URL`\n2. `ANTHROPIC_BASE_URL` (as `headroom wrap claude` sets it)\n3. `http://127.0.0.1:8787`\n\nOnly loopback URLs are used: `http` or `https` on exactly `localhost`, `127.0.0.1`\nor `[::1]`, with no user or password. A value that isn't one (a remote proxy, or a\nhost like `localhost.example.com`) is skipped, so the mod never polls a remote host.\n\n## Install\n\n```bash\nclaude plugin marketplace add headroomlabs-ai/headroom\nclaude plugin install headroom-snip@headroom-marketplace\n```\n\nOr, from a checkout: `claude --plugin-dir plugins/headroom-snip`.\n\n## Develop\n\n```bash\nclaude plugin validate plugins/headroom-snip\nclaude plugin test plugins/headroom-snip      # tests/snip.test.tsx\ntsc -p plugins/headroom-snip                  # after Claude Code has loaded it once\n```\n\n`hooks/snip.ts` holds the pure parts (parsing, transform labels, the animation\nframes) and `hooks/register.tsx` holds the hooks and drawing.\n","wiki/ARCHITECTURE.md":"# Headroom SDK: A Complete Explanation\n\n## Architecture Overview\n\n```mermaid\nflowchart TB\n    subgraph Entry[\"Entry Points\"]\n        Proxy[\"Proxy Mode<br/><i>Zero code changes</i>\"]\n        SDK[\"SDK Mode<br/><i>HeadroomClient</i>\"]\n        Integrations[\"Integrations<br/><i>LangChain / Agno</i>\"]\n    end\n\n    subgraph Pipeline[\"Transform Pipeline\"]\n        direction TB\n\n        CA[\"Cache Aligner<br/>━━━━━━━━━━━━━━━<br/>Extracts dynamic content<br/>(dates, UUIDs, tokens)<br/>Stable prefix for caching\"]\n\n        SC[\"Smart Crusher<br/>━━━━━━━━━━━━━━━<br/>Analyzes tool outputs<br/>Keeps: first, last, errors, outliers<br/>70-95% reduction\"]\n\n        CM[\"Context Manager<br/>━━━━━━━━━━━━━━━<br/>Enforces token limits<br/>Scores by recency and relevance<br/>Fits context window\"]\n\n        CA --> SC --> CM\n    end\n\n    subgraph Cache[\"Provider Cache Optimization\"]\n        direction LR\n        Anthropic[\"Anthropic<br/><i>cache_control blocks</i><br/>90% savings\"]\n        OpenAI[\"OpenAI<br/><i>Prefix alignment</i><br/>50% savings\"]\n        Google[\"Google<br/><i>CachedContent API</i><br/>75% savings\"]\n    end\n\n    subgraph CCR[\"CCR: Compress-Cache-Retrieve\"]\n        Store[(\"Compression<br/>Store\")]\n        Tool[\"Retrieve Tool<br/><i>LLM requests original</i>\"]\n        Store <--> Tool\n    end\n\n    LLM[\"LLM API<br/><i>OpenAI / Anthropic / Google</i>\"]\n\n    Entry --> Pipeline\n    Pipeline --> Cache\n    Cache --> LLM\n    SC -.->|\"Stores original\"| Store\n    LLM -.->|\"If needed\"| Tool\n```\n\n---\n\n## What Problem Does Headroom Solve?\n\nWhen you use AI models like GPT-4 or Claude, you pay for **tokens** - the pieces of text you send (input) and receive (output). The problem is:\n\n1. **Tool outputs are HUGE**: When an AI agent calls tools (search, database queries, APIs), the responses are often massive JSON blobs with thousands of tokens\n2. **Most of that data is REDUNDANT**: 60 metric data points showing `cpu: 45%` repeated, or 50 log entries with the same error message\n3. **You're paying for waste**: Every token costs money and adds latency\n4. **Context windows fill up**: Models have limits (128K tokens), and bloated tool outputs eat into your available space\n\n**Headroom creates \"headroom\"** - it intelligently compresses your input tokens so you have more room (and budget) for what matters.\n\n---\n\n## How Headroom Works: The Big Picture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        YOUR APPLICATION                          │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      HEADROOM CLIENT                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │\n│  │   ANALYZE   │→ │  TRANSFORM  │→ │    CALL     │             │\n│  │  (Parser)   │  │  (Pipeline) │  │   (API)     │             │\n│  └─────────────┘  └─────────────┘  └─────────────┘             │\n│         │                │                │                     │\n│         ▼                ▼                ▼                     │\n│   Count tokens     Apply compressions   Send to OpenAI/Claude  │\n│   Detect waste     Preserve meaning     Log metrics            │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                    OPENAI / ANTHROPIC API                        │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Core Components (In Simple Terms)\n\n### 1. HeadroomClient (`client.py`) - The Wrapper\n\n`HeadroomClient` is still exported (`headroom/__init__.py:93,197`), but it is\nno longer the only SDK entry point: the site's current architecture\ndocumentation (`docs/content/docs/architecture.mdx`) describes SDK mode as\ncalling the one-function `compress()` API (`headroom.compress`,\n`headroom.CompressConfig`) directly on your messages, with `HeadroomClient`\nas the client-wrapping alternative. Both exist; this section covers only the\nwrapper.\n\nThis is what you interact with. It wraps your existing OpenAI or Anthropic client:\n\n```python\n# Before (normal OpenAI)\nclient = OpenAI(api_key=\"...\")\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n\n# After (with Headroom)\nbase = OpenAI(api_key=\"...\")\nclient = HeadroomClient(original_client=base, provider=OpenAIProvider())\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n```\n\n**What it does:**\n- Intercepts your API calls\n- Runs messages through the transform pipeline\n- Calls the real API with optimized messages\n- Logs metrics to a database\n- Returns the response unchanged\n\n**Two modes:**\n- `audit`: Just observe and log (no changes)\n- `optimize`: Apply transforms to reduce tokens\n\n---\n\n### 2. Providers (`providers/`) - Model-Specific Knowledge\n\nDifferent AI providers have different rules:\n\n```python\nclass OpenAIProvider:\n    # Knows GPT-4o has 128K context\n    # Knows how to count tokens (tiktoken)\n    # Knows pricing ($2.50 per million input tokens)\n\nclass AnthropicProvider:\n    # Knows Claude has 200K context\n    # Uses different tokenization (~4 chars per token)\n    # Different pricing structure\n```\n\n**Why this matters:** Token counting is model-specific. GPT-4 uses different tokenization than Claude. Headroom needs accurate counts to know how much to compress.\n\n---\n\n### 3. Parser (`parser.py`) - Understanding Your Messages\n\nBefore optimizing, Headroom needs to understand what's in your messages:\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are helpful...\"},\n    {\"role\": \"user\", \"content\": \"Search for X\"},\n    {\"role\": \"assistant\", \"tool_calls\": [...]},\n    {\"role\": \"tool\", \"content\": \"{huge JSON}\"},\n]\n\n# Parser breaks this into \"blocks\":\nblocks = [\n    Block(kind=\"system\", tokens=50, ...),\n    Block(kind=\"user\", tokens=10, ...),\n    Block(kind=\"tool_call\", tokens=20, ...),\n    Block(kind=\"tool_result\", tokens=5000, ...),  # ← This is the problem!\n]\n```\n\n**It also detects waste signals:**\n- Large JSON blobs (>500 tokens)\n- HTML tags and comments\n- Base64 encoded data\n- Excessive whitespace\n\n---\n\n### 4. Transforms (`transforms/`) - The Compression Magic\n\nThis is where the real work happens. Headroom has 4 transforms that run in sequence:\n\n#### Transform 1: Cache Aligner\n\n**Problem:** LLM providers cache your prompts, but only if they're byte-identical. If your system prompt has today's date, every day is a cache miss.\n\n```python\n# Before:\n\"You are helpful. Current Date: 2024-12-15\"  # Changes daily = no cache\n\n# After:\n\"You are helpful.\"  # Static = cacheable\n\"[Context: Current Date: 2024-12-15]\"  # Dynamic part moved to end\n```\n\n**How it works:**\n1. Find date patterns in system prompt\n2. Extract them\n3. Move to end of message\n4. Now the PREFIX is stable → cache hits!\n\n---\n\n#### Transform 2: Tool Crusher (Naive) - DISABLED BY DEFAULT\n\nThis was our first approach - simple but limited:\n\n```python\n# Before: 60 items\n[{\"ts\": 1, \"cpu\": 45}, {\"ts\": 2, \"cpu\": 45}, ..., {\"ts\": 60, \"cpu\": 95}]\n\n# After: First 10 items only\n[{\"ts\": 1, \"cpu\": 45}, ..., {\"ts\": 10, \"cpu\": 45}, {\"__truncated\": 50}]\n```\n\n**Problem:** If the important data (CPU spike) is at position 45, it gets thrown away!\n\n---\n\n#### Transform 3: Smart Crusher (NEW DEFAULT)\n\nThis is the intelligent approach using **statistical analysis**:\n\n```python\n# Analyzes the data first:\nanalysis = {\n    \"ts\": {\"type\": \"sequential\", \"unique_ratio\": 1.0},\n    \"host\": {\"type\": \"constant\", \"value\": \"prod-1\"},  # ← Same everywhere!\n    \"cpu\": {\"variance\": 892, \"change_points\": [45]},  # ← Spike detected!\n}\n\n# Smart compression:\n{\n    \"__headroom_constants\": {\"host\": \"prod-1\"},  # Factor out\n    \"__headroom_summary\": \"items 0-44: cpu stable at ~45\",  # Summarize boring part\n    \"data\": [\n        {\"ts\": 45, \"cpu\": 92},  # Keep the spike!\n        {\"ts\": 46, \"cpu\": 95},\n        ...,\n    ],\n}\n```\n\n**Strategies it uses:**\n1. **TIME_SERIES**: Detect variance spikes, keep change points\n2. **CLUSTER**: Group similar log messages, keep 1-2 per cluster\n3. **TOP_N**: For search results, keep highest scored\n4. **SMART_SAMPLE**: Statistical sampling with constant extraction\n\n---\n\n#### Transform 4: ML Compressor (Optional, Kompress)\n\n**When to use:** Maximum compression needed and latency is acceptable.\n\nThe proxy ships an opt-in ML compression path backed by **Kompress**\n(ModernBERT-based token classifier). Install with `pip install\n'headroom-ai[ml]'`; see `wiki/transforms.md` for current configuration.\n\n**Note:** The earlier LLMLingua-2 integration (`--llmlingua` flag, the\n`headroom-ai[llmlingua]` extra, and the `LLMLinguaCompressor` class) was\nretired and replaced by Kompress. `pip install 'headroom-ai[llmlingua]'`\nno longer resolves; use `[ml]` instead.\n\n---\n\n#### Context Management: Live-Zone-Only Compression\n\n**Approach:** Headroom never drops messages from conversation history, and it does not do position-based or score-based context management. Context management is handled automatically inside the pipeline by compressing only the **live zone** — the newest content blocks (the latest user message and the latest tool result / tool output).\n\n```\n# The cache hot zone is NEVER mutated:\n# - System prompt\n# - Tool definitions\n# - Older conversation turns\n#\n# Only the newest content blocks are compressed (type-aware),\n# and every compression is reversible via CCR.\n```\n\n**Why this matters:** Leaving the hot zone untouched preserves provider prompt caching (e.g. Claude's cached-prefix read discount). Because only the newest blocks change, earlier turns stay byte-stable across requests and keep hitting the KV cache. Compression is type-aware (handled by ContentRouter and its compressors) and fully reversible — the LLM can call `headroom_retrieve` to restore any compressed block.\n\n---\n\n### 5. Storage (`storage/`) - Metrics Database\n\nEvery request is logged:\n\n```sql\nCREATE TABLE requests (\n    id TEXT PRIMARY KEY,\n    timestamp TEXT,\n    model TEXT,\n    mode TEXT,  -- audit or optimize\n    tokens_input_before INTEGER,  -- Before Headroom\n    tokens_input_after INTEGER,   -- After Headroom\n    tokens_saved INTEGER,         -- The win!\n    transforms_applied TEXT,      -- What we did\n    ...\n);\n```\n\nThis lets you:\n- See how much you're saving\n- Generate reports\n- Track trends over time\n\n---\n\n## The Data Flow (Step by Step)\n\nLet's trace a real request:\n\n### Step 1: You call the API\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are an SRE. Date: 2024-12-15\"},\n        {\"role\": \"user\", \"content\": \"Check the metrics\"},\n        {\"role\": \"assistant\", \"tool_calls\": [...]},\n        {\"role\": \"tool\", \"content\": \"{60 metric points...}\"},  # 5000 tokens!\n        {\"role\": \"user\", \"content\": \"What's wrong?\"},\n    ],\n    headroom_mode=\"optimize\",\n)\n```\n\n### Step 2: HeadroomClient intercepts\n```python\n# In client.py:\ndef _create(self, messages, ...):\n    # 1. Parse messages into blocks\n    blocks, breakdown, waste = parse_messages(messages, tokenizer)\n    # breakdown = {\"system\": 50, \"user\": 20, \"tool_result\": 5000, ...}\n\n    # 2. Count original tokens\n    tokens_before = 5100\n```\n\n### Step 3: Transform Pipeline runs\n```python\n# In pipeline.py:\ndef apply(self, messages, ...):\n    # Transform 1: Cache Aligner\n    # - Extracts \"Date: 2024-12-15\" from system prompt\n    # - Moves to end\n\n    # Transform 2: Smart Crusher\n    # - Analyzes 60 metric points\n    # - Detects CPU spike at point 45\n    # - Compresses to 17 points (preserving spike)\n    # - Factors out constant \"host\" field\n\n    # Transform 3: Kompress ML compressor (opt-in via headroom-ai[ml])\n    # - ModernBERT-based compression on remaining long text\n    # - Auto-detects content type for optimal rate\n    # - Stores original in CCR for retrieval\n\n    # Transform 4: Rolling Window\n    # - Checks if we're under limit (we are)\n    # - No drops needed\n\n    return TransformResult(\n        messages=optimized,\n        tokens_before=5100,\n        tokens_after=1200,  # 76% reduction!\n        transforms=[\"cache_align\", \"smart_crush:1\"]\n    )\n```\n\n### Step 4: Call real API\n```python\n# In client.py:\nresponse = self._original.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=optimized_messages,  # Only 1200 tokens now!\n)\n```\n\n### Step 5: Log metrics and return\n```python\n# Save to database\nmetrics = RequestMetrics(\n    tokens_input_before=5100,\n    tokens_input_after=1200,\n    tokens_saved=3900,  # 76%!\n    ...\n)\nstorage.save(metrics)\n\nreturn response  # Unchanged from API\n```\n\n---\n\n## The Smart Crusher Deep Dive\n\nThis is the most sophisticated part. Here's how it analyzes data:\n\n### Field Analysis\n```python\ndef analyze_field(key, items):\n    values = [item[key] for item in items]\n\n    return {\n        \"unique_ratio\": len(set(values)) / len(values),\n        # 0.0 = all same (constant)\n        # 1.0 = all different (unique IDs)\n        \"variance\": statistics.variance(values),  # For numbers\n        # Low = stable\n        # High = changing\n        \"change_points\": detect_spikes(values),\n        # Indices where value jumps significantly\n    }\n```\n\n### Pattern Detection\n```python\ndef detect_pattern(field_stats):\n    # Has timestamp + numeric variance? → TIME_SERIES\n    if has_timestamp and has_numeric_variance:\n        return \"time_series\"\n\n    # Has message field + level field? → LOGS\n    if has_message_field and has_level_field:\n        return \"logs\"\n\n    # Has score/rank field? → SEARCH_RESULTS\n    if has_score_field:\n        return \"search_results\"\n\n    return \"generic\"\n```\n\n### Compression Strategy\n```python\ndef compress(items, analysis):\n    if analysis.pattern == \"time_series\":\n        # Keep points around change points\n        # Summarize stable regions\n        return time_series_compress(items, analysis.change_points)\n\n    elif analysis.pattern == \"logs\":\n        # Cluster similar messages\n        # Keep 1-2 per cluster\n        return cluster_compress(items, analysis.clusters)\n\n    elif analysis.pattern == \"search_results\":\n        # Sort by score\n        # Keep top N\n        return top_n_compress(items, analysis.score_field)\n```\n\n---\n\n## CCR Architecture: Compress-Cache-Retrieve\n\n### The Key Insight\n\n> \"Prefer raw > Compaction > Summarization only when compaction no longer yields enough space. Compaction (Reversible) strips out information that is redundant because it exists in the environment—if the agent needs to read the data later, it can use a tool to retrieve it.\" — Phil Schmid, Context Engineering\n\n**The problem with traditional compression:** If we guess wrong about what's important, we've permanently lost data. The LLM might need something we threw away.\n\n**CCR's solution:** Make compression **reversible**. When SmartCrusher compresses, the original data is cached. If the LLM needs more, it can retrieve instantly.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  TOOL OUTPUT (1000 items)                                         │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  HEADROOM CCR LAYER                                               │\n│                                                                   │\n│  1. COMPRESS: Keep 20 items (errors, anomalies, relevant)        │\n│  2. CACHE: Store full 1000 items in fast local cache             │\n│  3. INJECT: Add retrieval capability to LLM context              │\n│                                                                   │\n│  \"20 items shown. Use /v1/retrieve?hash=xxx for more.\"           │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  LLM PROCESSING                                                   │\n│                                                                   │\n│  Option A: LLM solves task with 20 items → Done                  │\n│  Option B: LLM needs more → retrieves via API                    │\n│            → We fetch from cache → Return instantly              │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  FEEDBACK LOOP                                                    │\n│                                                                   │\n│  Track: What did the LLM retrieve? What queries?                 │\n│  Learn: \"For this tool, keep items matching common queries\"      │\n│  Improve: Next compression uses learned patterns                 │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### CCR Phase 1: Compression Store\n\n**Location:** `headroom/cache/compression_store.py`\n\nWhen SmartCrusher compresses, the original content is stored for on-demand retrieval:\n\n```python\n@dataclass\nclass CompressionEntry:\n    hash: str  # 24-char SHA256 prefix for retrieval\n    original_content: str  # Full JSON before compression\n    compressed_content: str  # Compressed JSON\n    original_item_count: int\n    compressed_item_count: int\n    tool_name: str | None  # For feedback tracking\n    created_at: float\n    ttl: int = 1800  # 30 minute default (DEFAULT_CCR_TTL_SECONDS)\n```\n\n**Features:**\n- Thread-safe in-memory storage\n- TTL-based expiration (default 30 minutes; `DEFAULT_CCR_TTL_SECONDS`, override via `HEADROOM_CCR_TTL_SECONDS`)\n- LRU-style eviction when capacity reached\n- Hash-keyed retrieval that always returns the full original content\n\n**Usage:**\n```python\nstore = get_compression_store()\n\n# Store compressed content\nhash_key = store.store(\n    original=original_json,\n    compressed=compressed_json,\n    original_item_count=1000,\n    compressed_item_count=20,\n    tool_name=\"search_api\",\n)\n\n# Retrieve later (by hash; always returns the full original content)\nentry = store.retrieve(hash_key)\n```\n\n---\n\n### CCR Phase 2: Retrieval API\n\n**Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/retrieve` | POST | Retrieve original content by hash |\n| `/v1/retrieve/{hash}` | GET | Retrieve original content by hash |\n\nRetrieval is by hash only — it always returns the full original content.\n\n**Retrieval Request:**\n```json\n{\n    \"hash\": \"abc123def456...\"\n}\n```\n\n**Response:**\n```json\n{\n    \"hash\": \"abc123def456...\",\n    \"original_content\": \"[{...}, {...}, ...]\",\n    \"original_item_count\": 1000,\n    \"tool_name\": \"search_api\"\n}\n```\n\n---\n\n### CCR Phase 3: Tool Injection\n\nWhen compression happens, Headroom injects retrieval instructions into the LLM context.\n\n**Method A: System Message Injection**\n```\n## Compressed Context Available\nThe following tool outputs have been compressed. If you need more detail,\ncall the retrieve_compressed tool with the hash.\n\nAvailable: hash=abc123 (1000→20 items from search_api)\n```\n\n**Method B: MCP Tool Registration (Hybrid)**\nWhen running as MCP server, Headroom exposes retrieval as a tool:\n\n```json\n{\n    \"name\": \"headroom_retrieve\",\n    \"description\": \"Retrieve more items from compressed tool output\",\n    \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"hash\": {\"type\": \"string\"}\n        },\n        \"required\": [\"hash\"]\n    }\n}\n```\n\n**Marker Injection:**\nCompressed content includes retrieval markers:\n```json\n{\n    \"__headroom_compressed\": true,\n    \"__headroom_hash\": \"abc123def456\",\n    \"__headroom_stats\": {\n        \"original_items\": 1000,\n        \"kept_items\": 20,\n        \"errors_preserved\": 5\n    },\n    \"data\": [...]\n}\n```\n\n---\n\n### CCR Phase 4: Feedback Loop\n\n**Location:** `headroom/cache/compression_feedback.py`\n\nThe feedback system learns from retrieval patterns to improve future compression.\n\n**Tracked Patterns per Tool:**\n```python\n@dataclass\nclass ToolPattern:\n    tool_name: str\n    total_compressions: int  # Times we compressed this tool\n    total_retrievals: int  # Times LLM asked for more\n    full_retrievals: int  # Retrieved everything (all retrievals — hash-only)\n    search_retrievals: int  # Legacy; always 0 (retrieval is hash-only, no search)\n    common_queries: dict[str, int]  # Legacy query-pattern frequency (no longer populated)\n    queried_fields: dict[str, int]  # Legacy queried-field frequency (no longer populated)\n```\n\n**Key Metrics:**\n- **Retrieval Rate**: `total_retrievals / total_compressions`\n  - High (>50%) → Compressing too aggressively\n  - Low (<20%) → Compression is effective\n- **Full Retrieval Rate**: `full_retrievals / total_retrievals`\n  - High (>80%) → Data is unique, consider skipping compression\n\n**Compression Hints:**\n```python\n@dataclass\nclass CompressionHints:\n    max_items: int = 15  # Target item count\n    suggested_items: int | None  # Calculated optimal\n    skip_compression: bool  # Don't compress at all\n    preserve_fields: list[str]  # Always keep these fields\n    aggressiveness: float  # 0.0 = aggressive, 1.0 = conservative\n    reason: str  # Explanation\n```\n\n**Feedback-Driven Adjustment:**\n```python\n# In SmartCrusher._crush_array()\nif self.config.use_feedback_hints and tool_name:\n    feedback = get_compression_feedback()\n    hints = feedback.get_compression_hints(tool_name)\n\n    if hints.skip_compression:\n        return items, f\"skip:feedback({hints.reason})\", None\n\n    if hints.suggested_items is not None:\n        self.config.max_items_after_crush = hints.suggested_items\n```\n\n**Feedback Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/feedback` | GET | Get all learned patterns |\n| `/v1/feedback/{tool_name}` | GET | Get hints for specific tool |\n\n**Example Response:**\n```json\n{\n    \"total_compressions\": 150,\n    \"total_retrievals\": 23,\n    \"global_retrieval_rate\": 0.15,\n    \"tools_tracked\": 5,\n    \"tool_patterns\": {\n        \"search_api\": {\n            \"compressions\": 50,\n            \"retrievals\": 5,\n            \"retrieval_rate\": 0.10,\n            \"full_rate\": 0.20,\n            \"search_rate\": 0.80,\n            \"common_queries\": [\"status:error\", \"level:critical\"],\n            \"queried_fields\": [\"status\", \"level\", \"message\"]\n        }\n    }\n}\n```\n\n---\n\n### CCR Phase 5: Response Handler (Automatic Tool Call Handling)\n\n**Location:** `headroom/ccr/response_handler.py`\n\n**The Problem:** When the proxy injects the `headroom_retrieve` tool, the LLM might call it. But who handles that tool call? Without response handling, the tool call would go back to the client unhandled.\n\n**The Solution:** The Response Handler intercepts LLM responses, detects CCR tool calls, executes retrievals automatically, and continues the conversation until the LLM produces a final response.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  RESPONSE HANDLER FLOW                                           │\n│                                                                   │\n│  1. LLM Response arrives                                         │\n│     └─ Contains: tool_use(headroom_retrieve, hash=abc123)       │\n│                                                                   │\n│  2. Handler detects CCR tool call                                │\n│     └─ Extracts hash                                             │\n│                                                                   │\n│  3. Handler executes retrieval                                   │\n│     └─ By hash: store.retrieve(hash) → full original content    │\n│                                                                   │\n│  4. Handler continues conversation                               │\n│     └─ Adds tool result to messages                             │\n│     └─ Makes another API call                                   │\n│                                                                   │\n│  5. Repeat until no CCR tool calls                              │\n│     └─ Max 3 rounds (configurable)                              │\n│                                                                   │\n│  6. Return final response to client                             │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CCRToolCall:\n    tool_call_id: str  # For matching response\n    hash_key: str  # CCR hash to retrieve\n\n\n@dataclass\nclass CCRToolResult:\n    tool_call_id: str\n    content: str  # Retrieved data as JSON\n    success: bool\n    items_retrieved: int\n\n\nclass CCRResponseHandler:\n    async def handle_response(\n        self,\n        response: dict,  # Initial LLM response\n        messages: list,  # Conversation history\n        tools: list,  # Tool definitions\n        api_call_fn: Callable,  # Function to make API calls\n        provider: str,  # \"anthropic\" or \"openai\"\n    ) -> dict:\n        \"\"\"Handle CCR tool calls until final response.\"\"\"\n```\n\n**Streaming Support:**\n\nThe handler also supports streaming responses via `StreamingCCRHandler`:\n\n```python\nclass StreamingCCRBuffer:\n    \"\"\"Buffers streaming chunks to detect CCR tool calls.\"\"\"\n\n    chunks: list[bytes]\n    detected_ccr: bool\n\n\nclass StreamingCCRHandler:\n    \"\"\"Handles CCR in streaming responses.\"\"\"\n\n    async def process_stream(self, stream, messages, tools, api_call_fn):\n        \"\"\"Yields chunks, switching to buffered mode if CCR detected.\"\"\"\n```\n\n---\n\n### CCR Phase 6: Context Tracker (Multi-Turn Awareness)\n\n**Location:** `headroom/ccr/context_tracker.py`\n\n**The Problem:** In multi-turn conversations, earlier compressed data might become relevant later. Without tracking, the LLM has \"context amnesia\" - it can't reference data that was compressed in turn 1 when answering a question in turn 5.\n\n**The Solution:** The Context Tracker maintains awareness of all compressed content across the conversation and can proactively expand relevant data when a new query might need it.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  CONTEXT TRACKER FLOW                                            │\n│                                                                   │\n│  Turn 1: Search returns 100 files → compressed to 10            │\n│          Tracker stores: hash=abc123, sample=\"auth.py, db.py\"   │\n│                                                                   │\n│  Turn 5: User asks \"What about the authentication middleware?\"  │\n│          Tracker analyzes query:                                 │\n│          - \"authentication\" matches \"auth.py\" in sample         │\n│          - Relevance score: 0.7 (above threshold)               │\n│                                                                   │\n│  Proactive Expansion:                                           │\n│          - Retrieves abc123 before LLM responds                 │\n│          - Adds expanded context to request                     │\n│                                                                   │\n│  Result: LLM sees full file list, can answer accurately         │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CompressedContext:\n    hash_key: str              # CCR hash\n    turn_number: int           # When compression happened\n    timestamp: float           # For age-based filtering\n    tool_name: str | None      # Which tool was compressed\n    original_item_count: int\n    compressed_item_count: int\n    query_context: str         # User query at compression time\n    sample_content: str        # Preview for relevance matching\n\n@dataclass\nclass ExpansionRecommendation:\n    hash_key: str\n    reason: str                # Human-readable explanation\n    relevance_score: float     # 0-1, higher = more relevant\n    # Expansion always restores the full original content (retrieval is by hash).\n\nclass ContextTracker:\n    def track_compression(self, hash_key, turn_number, ...):\n        \"\"\"Track a compression event.\"\"\"\n\n    def analyze_query(self, query: str) -> list[ExpansionRecommendation]:\n        \"\"\"Find relevant compressed contexts for a query.\"\"\"\n\n    def execute_expansions(self, recommendations) -> list[dict]:\n        \"\"\"Execute recommended expansions.\"\"\"\n```\n\n**Relevance Calculation:**\n\nThe tracker uses simple but effective heuristics:\n\n1. **Keyword overlap with sample content** - Extract keywords from query, match against compressed content preview\n2. **Keyword overlap with original query** - Match against the query that triggered compression\n3. **Tool name relevance** - File operations more likely to need expansion for \"file\", \"where\", \"find\" queries\n4. **Age discount** - Older contexts get lower scores\n\n**Configuration:**\n\n```python\n@dataclass\nclass ContextTrackerConfig:\n    enabled: bool = True\n    max_tracked_contexts: int = 100  # LRU eviction\n    relevance_threshold: float = 0.3  # Min score to recommend\n    max_context_age_seconds: float = 300  # 5 minutes\n    proactive_expansion: bool = True\n    max_proactive_expansions: int = 2  # Per query\n```\n\n---\n\n### Why CCR is a Moat\n\n1. **Reversible**: No permanent information loss. Worst case = retrieve everything.\n2. **Transparent**: LLM knows it can ask for more data.\n3. **Automatic**: Response Handler executes retrievals without client intervention.\n4. **Context-Aware**: Context Tracker prevents multi-turn amnesia.\n5. **Feedback Loop**: Learn from actual needs, not guesses.\n6. **Network Effect**: Retrieval patterns across users improve compression for everyone.\n7. **Zero-Risk**: If compression fails, instant fallback to original data.\n\n---\n\n## Image Compression Architecture\n\nVision models charge by the token, and images are expensive (765-2900 tokens for a typical image). Headroom's image compression uses a **trained ML router** to automatically select the optimal compression technique.\n\n### The Key Insight\n\nNot all image queries need full resolution:\n- \"What is this?\" → Low detail is fine (87% savings)\n- \"Count the whiskers\" → Need full detail (0% savings)\n- \"Read the sign\" → Could convert to text (99% savings)\n\n### How It Works\n\n```\nUser: [image] + \"What animal is this?\"\n           ↓\n┌─────────────────────────────────┐\n│  1. Query Analysis              │\n│  TrainedRouter (MiniLM)         │\n│  Classifies → full_low          │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  2. Image Analysis (Optional)   │\n│  SigLIP checks:                 │\n│  - Has text? Is complex?        │\n│  - Fine details needed?         │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  3. Apply Compression           │\n│  OpenAI: detail=\"low\"           │\n│  Anthropic: Resize to 512px     │\n│  Google: Resize to 768px        │\n└─────────────────────────────────┘\n           ↓\nCompressed request → LLM → Response\n```\n\n### The Trained Router\n\nA fine-tuned MiniLM classifier hosted on HuggingFace:\n\n- **Model**: `chopratejas/technique-router`\n- **Size**: ~128MB (downloaded once, cached)\n- **Accuracy**: 93.7% on 1,157 training examples\n- **Latency**: ~10ms CPU, ~2ms GPU\n\nThe router learns from examples like:\n| Query | Technique |\n|-------|-----------|\n| \"What is this?\" | `full_low` |\n| \"Count the items\" | `preserve` |\n| \"Read the text\" | `transcode` |\n| \"What's in the corner?\" | `crop` |\n\n### Provider-Specific Compression\n\nEach provider handles images differently:\n\n| Provider | Method | Savings |\n|----------|--------|---------|\n| **OpenAI** | `detail=\"low\"` parameter | ~87% |\n| **Anthropic** | PIL resize to 512px | ~75% |\n| **Google** | PIL resize to 768px (tile-optimized) | ~75% |\n\n### Integration Points\n\nImage compression runs in the proxy **before** text compression:\n\n```\nRequest arrives\n      ↓\n[Image Compression] ← NEW\n      ↓\n[Transform Pipeline: Cache Aligner → Smart Crusher → ...]\n      ↓\nForward to LLM\n```\n\nThis ensures images are compressed first, then text compression (CCR, SmartCrusher) handles the rest.\n\n### Code Location\n\n```\nheadroom/\n├── image/\n│   ├── __init__.py         # Public API\n│   ├── compressor.py       # ImageCompressor class\n│   └── trained_router.py   # TrainedRouter (HuggingFace model)\n├── proxy/\n│   └── server.py           # Integration point\n```\n\n---\n\n## File Structure Explained\n\n```\nheadroom/\n├── __init__.py          # Public exports\n├── client.py            # HeadroomClient - the main wrapper\n├── config.py            # All configuration dataclasses\n├── parser.py            # Message → Block decomposition\n├── tokenizer.py         # Token counting abstraction\n├── utils.py             # Hashing, markers, helpers\n│\n├── providers/\n│   ├── base.py          # Provider/TokenCounter protocols\n│   ├── openai.py        # OpenAI-specific (tiktoken)\n│   └── anthropic.py     # Anthropic-specific\n│\n├── transforms/\n│   ├── base.py              # Transform protocol\n│   ├── pipeline.py          # Orchestrates all transforms\n│   ├── cache_aligner.py     # Date extraction for caching\n│   ├── smart_crusher.py     # Statistical compression (default)\n│   ├── code_compressor.py   # AST-aware code compression (tree-sitter)\n│   └── (legacy llmlingua_compressor.py removed — see [ml] extra for Kompress;\n│        rolling_window.py / intelligent_context.py / scoring.py / tool_crusher.py\n│        removed — context management is now live-zone-only)\n│\n├── cache/               # CCR Architecture - Caching & Storage\n│   ├── compression_store.py    # Phase 1: Store original content\n│   ├── compression_feedback.py # Phase 4: Learn from retrievals\n│   ├── anthropic.py     # Anthropic cache optimizer\n│   ├── openai.py        # OpenAI cache optimizer\n│   ├── google.py        # Google cache optimizer\n│   └── dynamic_detector.py # Dynamic content detection\n│\n├── ccr/                 # CCR Architecture - Tool Injection & Response Handling\n│   ├── __init__.py             # CCR module exports\n│   ├── tool_injection.py       # Phase 3: Inject retrieval tool\n│   ├── response_handler.py     # Phase 5: Handle CCR tool calls\n│   ├── context_tracker.py      # Phase 6: Multi-turn context tracking\n│   └── mcp_server.py           # MCP server for retrieval tool\n│\n├── relevance/           # Relevance scoring for compression\n│   ├── bm25.py          # BM25 keyword scorer\n│   ├── embedding.py     # Semantic embedding scorer\n│   └── hybrid.py        # Adaptive fusion scorer\n│\n├── storage/\n│   ├── base.py          # Storage protocol\n│   ├── sqlite.py        # SQLite implementation\n│   └── jsonl.py         # JSON Lines implementation\n│\n├── proxy/\n│   └── server.py        # Production HTTP proxy (CCR endpoints)\n│\n└── reporting/\n    └── generator.py     # HTML report generation\n```\n\n---\n\n## Key Design Decisions\n\n### 1. Provider-Agnostic\nWorks with ANY OpenAI-compatible API:\n- OpenAI\n- Azure OpenAI\n- Anthropic\n- Groq\n- Together\n- Local models (Ollama)\n\n### 2. Deterministic Transforms\nNo LLM calls for compression. Everything is:\n- Statistical analysis\n- Pattern matching\n- Rule-based\n\nThis means:\n- Predictable results\n- Fast (<10ms overhead)\n- No added API costs\n\n### 3. Safety First\n- Never modify user/assistant TEXT content\n- Tool call + response are atomic (drop both or neither)\n- Parse failures = no-op (return unchanged)\n- Audit mode for testing before optimizing\n\n### 4. Smart by Default\n- SmartCrusher enabled (statistical, content-aware analysis — not naive rules)\n- Conservative settings that preserve important data\n\n---\n\n## What Makes This Different?\n\n### vs. Summarization (LLM-based compression)\n| Headroom | Summarization |\n|----------|---------------|\n| Deterministic | Non-deterministic |\n| ~10ms overhead | ~2-5 seconds overhead |\n| No extra API cost | Costs money to summarize |\n| Preserves structure | Loses structure |\n| Can't hallucinate | Can hallucinate |\n\n### vs. Simple Truncation\n| Headroom | Truncation |\n|----------|------------|\n| Keeps important data | Loses end of data |\n| Statistical analysis | No analysis |\n| Detects spikes | Misses spikes |\n| Factors out constants | Keeps redundancy |\n\n---\n\n## The Numbers (From Our Tests)\n\n> **Audit note (2026-09-02):** the specific token counts previously shown here\n> (a \"5 tool call SRE incident\" example) could not be traced to any benchmark,\n> test, or committed artifact in this repo and have been removed rather than\n> replaced with another unverified figure. For sourced compression numbers see\n> [Benchmarks](benchmarks.md) / `docs/content/docs/benchmarks.mdx`.\n\nReal-world SRE incident investigation (metrics, logs, status, deployments,\nrunbook tool calls in one turn) is the kind of workload SmartCrusher targets:\nstatistical, repetitive tool output where most of the redundancy is in\nconstant fields and stable regions, not in the handful of data points (spikes,\nerrors) that actually matter to the model's answer.\n\nThe model could still:\n- Identify the CPU spike (preserved by change point detection)\n- Reference specific error rates (kept in compressed data)\n- Provide correct remediation commands\n\n---\n\n## Summary\n\n**Headroom is a Context Budget Controller that:**\n\n1. **Wraps** your existing LLM client\n2. **Analyzes** your messages to find waste\n3. **Compresses** tool outputs intelligently (not blindly)\n4. **Preserves** important information (spikes, anomalies, unique data)\n5. **Logs** everything for observability\n6. **Saves** 70-90% of tokens on tool-heavy workloads\n\n**The key insight:** Most tool output redundancy is **statistical** (repeated values, constant fields, similar messages). By analyzing the data first, we can compress intelligently without losing the information that matters.\n","plugins/headroom-oauth2/README.md":"# headroom-oauth2\n\nGeneric **OAuth2 client-credentials** upstream-auth extension for the\n[Headroom](https://github.com/headroomlabs-ai/headroom) proxy.\n\nWhen Headroom routes to an OpenAI-compatible backend that is protected by an\nOAuth2 client-credentials flow (enterprise AI gateways, Azure AD / Entra, Okta,\nAuth0, Keycloak, Cognito, …), this extension mints a bearer token from a\nconfigurable token endpoint, caches + refreshes it (single-flight), and injects\n`Authorization: Bearer <token>` on each upstream request. Optional static upstream\nheaders are sent via litellm. **Fully vendor-neutral — no provider is hard-coded.**\n\nIt plugs into Headroom's public `headroom.proxy_extension` entry-point seam, so it\nis fully out-of-tree and opt-in.\n\n## Install & enable\n```bash\npip install headroom-oauth2\nheadroom proxy --backend litellm-openai --proxy-extension oauth2\n```\n\n## Configure (env; no-op unless HEADROOM_OAUTH2_TOKEN_URL is set)\n| Env | Meaning |\n|-----|---------|\n| `HEADROOM_OAUTH2_TOKEN_URL` | token endpoint (client_credentials grant) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | credentials (secrets) |\n| `HEADROOM_OAUTH2_SCOPES` | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | optional audience |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | static upstream headers, `K=V,K2=V2` |\n\nTokens are minted with the standard library (`urllib`, system cert store), which\nworks behind corporate SSL-inspection where bundled-root TLS stacks fail.\n\n\n**Effective backends:** the injected bearer reaches the upstream only for OpenAI-compatible /\npassthrough litellm providers. `bedrock` / `vertex` / `sagemaker` authenticate from env and\nignore it, so this extension is a no-op there (it logs a warning at startup).\n\n**Transport:** `token_url` must be `https` (loopback `http` is allowed for tests; set\n`HEADROOM_OAUTH2_ALLOW_INSECURE=1` to override). Tokens are minted with the standard library\n(`urllib`, system cert store), so a corporate-injected CA is trusted without bundling roots.\n\n## What gets the upstream bearer\n\nThe minted token is injected only on requests that **go upstream**. Routes the\nproxy answers itself — `/health`, `/livez`, `/readyz`, `/stats*`, `/metrics`,\n`/quota`, `/settings*`, `/dashboard*`, `/admin/*`, `/debug/*`, `/v1/compress*`,\n`/v1/usage`, `/v1/retrieve*`, `/v1/telemetry*`, `/v1/toin*`, `/v1/feedback*`,\nand any extension route under `/ext/` — are passed through untouched, so an\nunreachable IdP never turns a health probe into a 502 and management calls never\ncost a token mint. A `/p/<project>/` base-URL prefix is stripped before the\ncheck.\n\nRequires `headroom-ai` ≥ 0.40, where extension middleware runs inside the\nproxy's `HEADROOM_PROXY_TOKEN` gate: clients may then authenticate with\n`Authorization: Bearer <proxy token>` and the gate checks it before this\nextension replaces it with the upstream bearer.\n","plugins/headroom-agent-hooks/README.md":"# Headroom agent hooks\r\n\r\nThis plugin exposes lightweight startup hooks for Claude Code and GitHub Copilot CLI.\r\n\r\nThe hooks resolve and call:\n\r\n```bash\r\nheadroom init hook ensure\r\n```\r\n\r\nThat hidden helper checks for a matching durable `headroom init` deployment and starts it if needed.\n\nWhen `CLAUDE_PLUGIN_ROOT` points to a readable launcher, resolution order is\n`HEADROOM_BIN`, `headroom` on `PATH`, then `headroom` and\n`headroom.exe` in `$HOME/.local/bin`, `$HOME/.local/share/uv/tools/headroom-ai/bin`,\n`${PIPX_HOME:-$HOME/.local/pipx}/venvs/headroom-ai/bin`, `/opt/homebrew/bin`, and\n`/usr/local/bin`. If no executable is found, `HEADROOM_PYTHON`, `python3`, and\n`python` are checked for an importable `headroom` module and invoked as\n`python -m headroom.cli init hook ensure`.\n\nSet `HEADROOM_BIN` or `HEADROOM_PYTHON` to override discovery. An absent CLI emits\none actionable diagnostic and exits successfully, so the host hook remains\nnonblocking. Without a readable launcher, the hook runs bare\n`headroom init hook ensure` from `PATH` with none of the discovery above. Copilot\nCLI on Windows uses the manifest's `powershell` entry, which does the same.\n","plugins/headroom-oauth2/SPEC.md":"# Spec — `headroom-oauth2` (generic OAuth2 client-credentials upstream auth)\n\n## Summary\n\nA vendor-neutral proxy extension (registers on Headroom's `headroom.proxy_extension` seam) that\nmints an OAuth2 **client-credentials** (RFC 6749 §4.4) bearer from a configured token endpoint and\ninjects it as the upstream `Authorization` on every proxied request. Lets Headroom front any\ngateway that requires a minted machine token (not a static API key) — with **zero core changes**\nand **no vendor specifics** (the gateway is entirely config/env).\n\nIt complements `#510` (env-var auth), which assumes a long-lived static key; this covers the\n\"mint-then-refresh a short-lived token\" case.\n\n## API surface (config / CLI / env)\n\nOpt-in only, via Headroom's existing flags — **no new CLI flags**:\n\n    headroom proxy --backend litellm-openai --proxy-extension oauth2\n    # or HEADROOM_PROXY_EXTENSIONS=oauth2\n\nAll configuration is env (12-factor; nothing baked in):\n\n| Env var | Required | Meaning |\n|---|---|---|\n| `HEADROOM_OAUTH2_TOKEN_URL` | yes (else no-op) | OAuth2 token endpoint; must be `https` (loopback `http` allowed for tests) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | yes | client credentials |\n| `HEADROOM_OAUTH2_SCOPES` | no | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | no | `audience` form param |\n| `HEADROOM_OAUTH2_RESOURCE` | no | RFC 8707 target `resource` form param |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | no | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | no | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | no | static upstream headers, `K=V,K2=V2` (control chars rejected) |\n| `HEADROOM_OAUTH2_TIMEOUT` / `_SKEW` | no | token request timeout / pre-expiry refresh skew (s) |\n| `HEADROOM_OAUTH2_ALLOW_INSECURE` | no | `1` to allow a non-loopback `http` token_url (discouraged) |\n\nPublic Python API: `OAuth2ClientCredentials`, `OAuth2Middleware`, `OAuth2Error`, `install`,\n`provider_from_env`, `parse_headers`.\n\n## Changes to existing behavior / defaults / compatibility\n\n- **None unless explicitly enabled.** The entry point is dormant until `--proxy-extension oauth2`\n  is passed, and even then a **no-op** unless `HEADROOM_OAUTH2_TOKEN_URL` is set.\n- When active, it **overwrites the request `Authorization` header** with the minted bearer before\n  the backend runs. The client's own `Authorization`/`x-api-key` is intentionally replaced (the\n  proxy authenticates to the gateway on the client's behalf). *Compatibility note:* because the\n  request then carries a bearer, Headroom classifies it as OAuth-mode auth — same as supplying a\n  bearer yourself; no new classification path.\n- No change to defaults, the request/response body, model routing, or compression.\n\n## User stories (Given / When / Then)\n\n- **Golden path** — *Given* a proxy started with `--proxy-extension oauth2` and valid\n  `TOKEN_URL`/`CLIENT_ID`/`CLIENT_SECRET`, *When* a client sends `/v1/messages`, *Then* the\n  extension mints (or reuses a cached) bearer and the upstream receives `Authorization: Bearer\n  <minted>` plus any static headers; the client never sees the secret.\n- **Edge: token endpoint down** — *Given* an unreachable/erroring `TOKEN_URL`, *When* a request\n  arrives, *Then* the proxy returns `502 upstream_auth_error` (no upstream call, no secret/body\n  leak) and stays up; the next request retries.\n- **Edge: wrong backend** — *Given* `--backend bedrock` (env-auth), *When* the extension installs,\n  *Then* it logs a loud warning that the injected bearer will have no effect and to use an\n  OpenAI-compatible/passthrough backend.\n\n## Failure modes & recovery\n\n| Failure | Behavior |\n|---|---|\n| Missing/invalid config at startup | `install()` raises -> proxy **fails closed** (won't start mis-auth'd) |\n| Token endpoint unreachable / non-2xx / non-JSON / no `access_token` | `OAuth2Error` -> `502`, per-request, proxy stays up, retried next request |\n| `expires_in` = 0/negative/absent | clamped to a positive TTL (never stale, never per-request mint) |\n| Concurrent first requests | single-flight lock -> exactly one mint per refresh |\n| Malformed `HEADROOM_OAUTH2_HEADERS` (CR/LF) | offending pair dropped with a warning (no header injection) |\n\n## Resilience (Docker / native / wrappers / providers / multi-process)\n\n- **Native & Docker:** identical; pure env-driven, std-lib only. Token minted via `urllib` against\n  the **system cert store**, so a corporate-injected CA is trusted with no bundled roots (works in\n  SSL-inspection networks).\n- **Wrappers (`headroom wrap`, agent hooks):** the extension lives at the proxy layer, so anything\n  routed through the proxy inherits it transparently.\n- **Providers:** effective for OpenAI-compatible / passthrough litellm backends (those that forward\n  the request bearer upstream). `bedrock`/`vertex`/`sagemaker` authenticate from env and ignore the\n  bearer -> the extension warns and is a no-op there.\n- **Multi-process (multiple workers):** the token cache is per-process; each worker mints/refreshes\n  independently. Acceptable for client-credentials (idempotent, low rate); no shared state, no\n  cross-process lock needed. Documented so operators can size token-endpoint rate limits.\n\n## Security & privacy\n\n- Secrets are env-only; **never logged** and **never returned** to the client.\n- The IdP error body is **drained, not surfaced** (may echo sensitive context).\n- `token_url` is **https-enforced** (loopback exception for tests; explicit opt-out env).\n- The minted bearer is sent only to the configured upstream; the client's inbound credential is\n  replaced, not forwarded onward.\n\n## Observability / logging / telemetry\n\n- `INFO` on install (token_url + auth style, no secrets) and on each mint (`ttl`, scopes).\n- `WARNING` on mint failure, env-auth-backend no-op, and dropped malformed static headers.\n- No metrics/telemetry emitted; piggybacks on Headroom's existing request logging. (A future\n  counter for mint/refresh/failure could be added if maintainers want it.)\n\n## Rollback / migration\n\n- **No migration** — additive and opt-in; existing deployments are unaffected.\n- **Instant rollback:** drop `--proxy-extension oauth2` (or unset `HEADROOM_PROXY_EXTENSIONS`), or\n  uninstall the package. No state to clean up, no config format changes.\n\n## Dependencies\n\n- **Runtime:** standard library only (no new core dependency). `litellm` is touched **only** if\n  `HEADROOM_OAUTH2_HEADERS` is set, and it is already a Headroom backend dependency — declared here\n  as the optional `[litellm]` extra, not a hard requirement.\n","plugins/headroom-snip/tsconfig.json":"# Headroom-snip Skill\n\nPath: `plugins/headroom-snip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/tsconfig.json)","plugins/hermes/README.md":"# hermes Documentation\n\nPath: `plugins/hermes/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/README.md)","plugins/openclaw/README.md":"# openclaw Documentation\n\nPath: `plugins/openclaw/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/README.md)","plugins/openclaw/openclaw.plugin.json":"# openclaw Plugin Manifest\n\nPath: `plugins/openclaw/openclaw.plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/openclaw.plugin.json)","plugins/openclaw/package-lock.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package-lock.json)","plugins/openclaw/package.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package.json)","plugins/openclaw/tsconfig.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/tsconfig.json)","plugins/opencode/README.md":"# opencode Documentation\n\nPath: `plugins/opencode/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/README.md)","plugins/opencode/package-lock.json":"# Opencode Skill\n\nPath: `plugins/opencode/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package-lock.json)","plugins/opencode/package.json":"# Opencode Skill\n\nPath: `plugins/opencode/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package.json)","plugins/opencode/tsconfig.json":"# Opencode Skill\n\nPath: `plugins/opencode/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/tsconfig.json)","e2e/wrap/tools/README.md":"# tools Documentation\n\nPath: `e2e/wrap/tools/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/README.md)","e2e/wrap/tools/package-lock.json":"# Tools Skill\n\nPath: `e2e/wrap/tools/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package-lock.json)","e2e/wrap/tools/package.json":"# Tools Skill\n\nPath: `e2e/wrap/tools/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package.json)","plugins/headroom-agent-hooks/.claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.claude-plugin/plugin.json)","plugins/headroom-agent-hooks/hooks/hooks.json":"# Hooks Skill\n\nPath: `plugins/headroom-agent-hooks/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/hooks/hooks.json)","plugins/headroom-snip/.claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-snip/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/.claude-plugin/plugin.json)","plugins/headroom-snip/hooks/hooks.json":"# Hooks Skill\n\nPath: `plugins/headroom-snip/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/hooks/hooks.json)","plugins/hermes/headroom_retrieve/plugin.yaml":"# Headroom_retrieve Skill\n\nPath: `plugins/hermes/headroom_retrieve/plugin.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/headroom_retrieve/plugin.yaml)","plugins/openclaw/hook-shim/HOOK.md":"# Hook-shim Skill\n\nPath: `plugins/openclaw/hook-shim/HOOK.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/hook-shim/HOOK.md)","plugins/headroom-agent-hooks/.github/plugin/plugin.json":"# plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.github/plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.github/plugin/plugin.json)"},"files":{".claude-plugin/marketplace.json":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    },\n    {\n      \"name\": \"headroom-snip\",\n      \"source\": \"./plugins/headroom-snip\",\n      \"description\": \"Claude Code mod: watch Headroom snip tokens off every request, with an animated band, a /headroom log and a running total.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"claude-code\",\n        \"tokens\",\n        \"compression\",\n        \"mod\"\n      ]\n    }\n  ]\n}\n","llms.txt":"# Headroom\n\n> Context optimization layer for LLM applications. Compress tool outputs, logs, files, and RAG chunks before they reach the model. Same answers, 60–95% fewer tokens. Library, proxy, and MCP server. Apache 2.0, local-first.\n\nHeadroom is shipped as a Python package (`headroom-ai`), a TypeScript package (`headroom-ai`), an OpenAI + Anthropic-compatible HTTP proxy (`headroom proxy`), and an MCP server (`headroom_compress`, `headroom_retrieve`, `headroom_stats` tools). All four modes use the same compression pipeline: per-content-type compressors (JSON, code, logs, diffs, text) feed into a Compress-Cache-Retrieve (CCR) store so compression stays reversible — the LLM can ask for the original whenever it wants.\n\nThe canonical, always-current documentation index lives at the docs site below. If you can fetch one URL, fetch that one; the entries here are a hand-curated subset.\n\n## Canonical docs (start here)\n\n- [Live llms.txt (full doc index)](https://docs.headroomlabs.ai/llms.txt): Auto-generated index of every doc page with descriptions.\n- [Live llms-full.txt (every doc page concatenated)](https://docs.headroomlabs.ai/llms-full.txt): One Markdown blob containing every doc page. Use when you can spend the tokens for full context.\n- [Docs site](https://docs.headroomlabs.ai/docs): Human-browsable docs with search.\n- [GitHub repo](https://github.com/headroomlabs-ai/headroom): Source, issues, releases.\n- [PyPI package](https://pypi.org/project/headroom-ai/): Python install.\n- [npm package](https://www.npmjs.com/package/headroom-ai): TypeScript install.\n\n## Install (copy-paste-runnable)\n\n- Python: `pip install headroom-ai` (add `[all]` for every optional extra)\n- TypeScript / Node: `npm install headroom-ai` (or `pnpm add headroom-ai`, `bun add headroom-ai`)\n- Docker local: `docker run --rm -p 127.0.0.1:8787:8787 ghcr.io/headroomlabs-ai/headroom:latest --host 0.0.0.0`\n- Run the proxy: `headroom proxy --port 8787` then point any client at `http://127.0.0.1:8787`\n- Wrap an agent in one command: `headroom wrap claude` (also: `codex`, `copilot`, `cursor`, `aider`, `opencode`, `cline`, `continue`, `goose`, `openhands`, `openclaw`, `vibe`, `omp`)\n\n## Entry points\n\n- [Quickstart](https://docs.headroomlabs.ai/docs/quickstart): 5-minute end-to-end (install → compress → call the model).\n- [Installation](https://docs.headroomlabs.ai/docs/installation): All install paths, extras, Docker tags, env vars.\n- [Proxy server](https://docs.headroomlabs.ai/docs/proxy): Run as a local HTTP proxy in front of OpenAI / Anthropic / Gemini.\n- [MCP server](https://docs.headroomlabs.ai/docs/mcp): `headroom_compress`, `headroom_retrieve`, `headroom_stats` for Claude Code / Cursor / any MCP host.\n- [API reference](https://docs.headroomlabs.ai/docs/api-reference): Python + TypeScript `compress()` API.\n\n## How it works\n\n- [How compression works](https://docs.headroomlabs.ai/docs/how-compression-works): Three-stage pipeline + automatic content routing.\n- [SmartCrusher](https://docs.headroomlabs.ai/docs/smart-crusher): Statistical JSON / array compression (70–90% on tool outputs).\n- [Code compression](https://docs.headroomlabs.ai/docs/code-compression): AST-aware via tree-sitter (preserves imports, signatures, types).\n- [Text & log compression](https://docs.headroomlabs.ai/docs/text-and-logs): Search results, build logs, diffs.\n- [CCR (reversible)](https://docs.headroomlabs.ai/docs/ccr): Compress-Cache-Retrieve — originals never deleted; LLM retrieves on demand.\n\n## SDK / framework integrations\n\n- [Anthropic SDK](https://docs.headroomlabs.ai/docs/anthropic-sdk): `withHeadroom(anthropic)` wrapper.\n- [OpenAI SDK](https://docs.headroomlabs.ai/docs/openai-sdk): `withHeadroom(openai)` wrapper.\n- [Vercel AI SDK](https://docs.headroomlabs.ai/docs/vercel-ai-sdk): Middleware + `withHeadroom()`.\n- [LangChain](https://docs.headroomlabs.ai/docs/langchain): Chat models, memory, retrievers, agents.\n- [Agno](https://docs.headroomlabs.ai/docs/agno): Model wrapping + observability hooks.\n- [Strands](https://docs.headroomlabs.ai/docs/strands): Model wrapping + hook-based tool output compression.\n- [LiteLLM](https://docs.headroomlabs.ai/docs/litellm): Single callback; works with all 100+ LiteLLM providers.\n\n## Memory & cross-agent state\n\n- [Persistent memory](https://docs.headroomlabs.ai/docs/memory): Per-project SQLite + HNSW vector store. No cross-project bleed (GH #462).\n- [SharedContext](https://docs.headroomlabs.ai/docs/shared-context): Compressed inter-agent context handoffs.\n- [Failure learning](https://docs.headroomlabs.ai/docs/failure-learning): Offline analysis writes corrections to `CLAUDE.local.md` (default, gitignored) or `CLAUDE.md` (shared) / `AGENTS.md` / `GEMINI.md`.\n\n## Operations\n\n- [Configuration](https://docs.headroomlabs.ai/docs/configuration): Env vars, config file, per-call overrides.\n- [Benchmarks](https://docs.headroomlabs.ai/docs/benchmarks): Token-savings numbers across content types.\n- [Troubleshooting](https://docs.headroomlabs.ai/docs/troubleshooting): Common failure modes and fixes.\n- [Limitations](https://docs.headroomlabs.ai/docs/limitations): What Headroom won't do well today.\n\n## Headroom for Teams\n\nFor teams and companies that want Headroom across every developer rather than one laptop: Headroom Enterprise adds more savings (tool search for every model, harness tuning, extra compressors), automatic model routing (open source has opt-in, rule-based routing), prompt-injection and risky-tool-call removal, SSO, managed or VPC deployment, an org-wide savings dashboard, and support. Companies that sign a 12-month Enterprise plan get the first 3 months free.\n\n- [Headroom for Teams](https://docs.headroomlabs.ai/docs/teams): Open source vs Enterprise, and the 3-months-free offer.\n- [Claim 3 months free](https://headroom-perks.vercel.app/?source=github&utm_source=llms-txt): Perk sign-up form. One perk per company.\n\n## Licensing\n\nApache 2.0. Use commercially, modify, redistribute. Data stays on the user's machine when running the library, proxy, or MCP server locally. An anonymous usage beacon is **on by default**: it reports compression ratios, counters, provider and model IDs, OS and architecture, and never prompts, completions, code or file paths. Turn it off with `HEADROOM_BEACON=off`, `DO_NOT_TRACK=1`, or `HEADROOM_OFFLINE=1`. See [Telemetry](https://github.com/headroomlabs-ai/headroom#telemetry).\n","wiki/api.md":"# API Reference\n\n## HeadroomClient\n\nThe main entry point for Headroom SDK.\n\n```python\nfrom headroom import HeadroomClient\nfrom openai import OpenAI\n\nclient = HeadroomClient(\n    original_client=OpenAI(),\n    default_mode=\"optimize\",\n)\n```\n\n### Constructor Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `original_client` | `OpenAI \\| Anthropic` | Required | The underlying LLM client |\n| `provider` | `Provider` | Required (no default) | Token counting provider — e.g. `OpenAIProvider()`, `AnthropicProvider()` |\n| `default_mode` | `str` | `\"audit\"` | Default mode: \"audit\", \"optimize\", \"off\" |\n| `store_url` | `str` | `None` | Storage URL for metrics |\n| `model_context_limits` | `dict[str, int]` | `None` | Override context limits for models |\n| `cache_optimizer` | `BaseCacheOptimizer` | `None` (auto-detect) | Custom cache optimizer |\n| `enable_cache_optimizer` | `bool` | `True` | Enable provider-specific cache optimization |\n| `enable_semantic_cache` | `bool` | `False` | Enable query-level semantic caching |\n| `config` | `HeadroomConfig` | `None` | Full config object; set `config.smart_crusher` / `config.cache_aligner` here to override compression/cache-alignment settings — there is no separate `smart_crusher_config`/`cache_aligner_config` constructor kwarg |\n\n### Methods\n\n#### `chat.completions.create(**kwargs)`\n\nCreate a chat completion with optional optimization.\n\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[...],\n    headroom_mode=\"optimize\",  # Override default mode\n)\n```\n\n**Additional Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `headroom_mode` | `str` | Override mode for this request |\n| `headroom_query` | `str` | Query for relevance scoring |\n\n#### `chat.completions.simulate(**kwargs)`\n\nPreview optimization without making an API call.\n\n```python\nplan = client.chat.completions.simulate(\n    model=\"gpt-4o\",\n    messages=[...],\n)\n\nprint(f\"Tokens before: {plan.tokens_before}\")\nprint(f\"Tokens after: {plan.tokens_after}\")\nprint(f\"Savings: {plan.savings_percent:.1f}%\")\n```\n\n**Returns:** `SimulationResult`\n\n---\n\n## Configuration Classes\n\n### SmartCrusherConfig\n\n```python\nfrom headroom import SmartCrusherConfig\n\nconfig = SmartCrusherConfig(\n    min_tokens_to_crush=200,\n    max_items_after_crush=50,\n    keep_first=3,\n    keep_last=2,\n    relevance_threshold=0.3,\n    anomaly_std_threshold=2.0,\n    preserve_errors=True,\n)\n```\n\n### CacheAlignerConfig\n\n```python\nfrom headroom import CacheAlignerConfig\n\nconfig = CacheAlignerConfig(\n    extract_dates=True,\n    normalize_whitespace=True,\n    stable_prefix_min_tokens=100,\n)\n```\n\n### RelevanceScorerConfig\n\n```python\nfrom headroom import RelevanceScorerConfig\n\nconfig = RelevanceScorerConfig(\n    scorer_type=\"bm25\",  # \"bm25\", \"embedding\", or \"hybrid\"\n    embedding_model=None,  # Model name for embedding scorer\n    hybrid_alpha=0.5,  # Weight for hybrid scoring\n)\n```\n\n---\n\n## Data Models\n\n### SimulationResult\n\nReturned by `simulate()`.\n\n```python\n@dataclass\nclass SimulationResult:\n    tokens_before: int\n    tokens_after: int\n    tokens_saved: int\n    savings_percent: float\n    transforms_applied: list[str]\n    waste_signals: WasteSignals\n```\n\n### RequestMetrics\n\nMetrics for a single request.\n\n```python\n@dataclass\nclass RequestMetrics:\n    request_id: str\n    timestamp: datetime\n    model: str\n    tokens_input_before: int\n    tokens_input_after: int\n    tokens_output: int\n    cost_before: float\n    cost_after: float\n    transforms_applied: list[str]\n```\n\n### WasteSignals\n\nDetected waste in the request.\n\n```python\n@dataclass\nclass WasteSignals:\n    json_bloat_tokens: int\n    html_noise_tokens: int\n    whitespace_tokens: int\n    dynamic_date_tokens: int\n    repetition_tokens: int\n```\n\n---\n\n## Providers\n\n### OpenAIProvider\n\n```python\nfrom headroom import OpenAIProvider\n\nprovider = OpenAIProvider()\n\n# Get token counter\ncounter = provider.get_token_counter(\"gpt-4o\")\ntokens = counter.count_text(\"Hello, world!\")\n\n# Get context limit\nlimit = provider.get_context_limit(\"gpt-4o\")  # 128000\n\n# Estimate cost\ncost = provider.estimate_cost(\n    input_tokens=1000,\n    output_tokens=500,\n    model=\"gpt-4o\",\n)\n```\n\n### AnthropicProvider\n\n```python\nfrom headroom import AnthropicProvider\nfrom anthropic import Anthropic\n\nprovider = AnthropicProvider(client=Anthropic())\n\ncounter = provider.get_token_counter(\"claude-3-5-sonnet-latest\")\ntokens = counter.count_messages(messages)  # Accurate count via API\n```\n\n---\n\n## Relevance Scoring\n\n### BM25Scorer\n\nFast keyword-based scoring (zero dependencies).\n\n```python\nfrom headroom import BM25Scorer\n\nscorer = BM25Scorer()\nscores = scorer.score_items(\n    items=[\"item 1\", \"item 2\", ...],\n    query=\"search query\",\n)\n```\n\n### EmbeddingScorer\n\nSemantic similarity scoring (requires `sentence-transformers`).\n\n```python\nfrom headroom import EmbeddingScorer, embedding_available\n\nif embedding_available():\n    scorer = EmbeddingScorer(model=\"all-MiniLM-L6-v2\")\n    scores = scorer.score_items(items, query)\n```\n\n### HybridScorer\n\nCombines BM25 and embeddings.\n\n```python\nfrom headroom import HybridScorer\n\nscorer = HybridScorer(alpha=0.5)  # 50% BM25, 50% embedding\nscores = scorer.score_items(items, query)\n```\n\n### create_scorer()\n\nFactory function to create scorers.\n\n```python\nfrom headroom import create_scorer\n\n# Auto-select best available scorer\nscorer = create_scorer()\n\n# Explicitly choose type\nscorer = create_scorer(scorer_type=\"hybrid\", alpha=0.7)\n```\n\n---\n\n## Transforms (Direct Use)\n\n### SmartCrusher\n\n```python\nfrom headroom import SmartCrusher\n\ncrusher = SmartCrusher()\nresult = crusher.crush(\n    data={\"results\": [...]},\n    query=\"user query\",\n)\n```\n\n### CacheAligner\n\n```python\nfrom headroom import CacheAligner\n\naligner = CacheAligner()\nresult = aligner.align(messages)\n```\n\n> **Context management** is handled automatically inside the pipeline\n> (live-zone-only compression). The position-based `RollingWindow` and\n> score-based `IntelligentContextManager` / `MessageScorer` APIs have been\n> removed and are no longer part of Headroom.\n\n### TransformPipeline\n\n```python\nfrom headroom import TransformPipeline\n\npipeline = TransformPipeline(\n    [\n        SmartCrusher(),\n        CacheAligner(),\n    ]\n)\n\nresult = pipeline.transform(messages)\n```\n\n---\n\n## Utilities\n\n### Tokenizer\n\n```python\nfrom headroom import Tokenizer, count_tokens_text, count_tokens_messages\n\n# Quick counting\ntokens = count_tokens_text(\"Hello, world!\", model=\"gpt-4o\")\n\n# With tokenizer instance\ntokenizer = Tokenizer(model=\"gpt-4o\")\ntokens = tokenizer.count_text(\"Hello\")\ntokens = tokenizer.count_messages(messages)\n```\n\n### generate_report()\n\nGenerate HTML/Markdown reports from stored metrics.\n\n```python\nfrom headroom import generate_report\n\nreport = generate_report(\n    store_url=\"sqlite:///headroom.db\",\n    format=\"html\",\n    period=\"day\",\n)\n```\n\n---\n\n## TypeScript SDK\n\nFor the TypeScript SDK API reference, see [TypeScript SDK](typescript-sdk.md).\n\nThe TypeScript SDK provides `compress()`, `HeadroomClient`, and framework adapters for Vercel AI SDK, OpenAI, and Anthropic.\n",".github/plugin/marketplace.json":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    }\n  ]\n}\n","headroom/evals/README.md":"# Headroom Evaluation Framework\n\n**Prove that compression preserves LLM accuracy through rigorous OSS benchmarks.**\n\n## Results\n\n### Standard Benchmarks — \"No Accuracy Loss\"\n\n| Benchmark | Category | N | Baseline | Headroom | Delta |\n|-----------|----------|---|----------|----------|-------|\n| [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |\n| [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |\n\n### Compression Benchmarks — \"Big Savings, Accuracy Preserved\"\n\n| Benchmark | Category | N | Accuracy | Compression | Method |\n|-----------|----------|---|----------|-------------|--------|\n| [SQuAD v2](https://huggingface.co/datasets/rajpurkar/squad_v2) | QA | 100 | **97%** | 19% | Before/After |\n| [BFCL](https://huggingface.co/datasets/gorilla-llm/Berkeley-Function-Calling-Leaderboard) | Tool/Function | 100 | **97%** | 32% | LLM-as-Judge |\n| Tool Outputs (built-in) | Agent | 8 | **100%** | 20% | Before/After + Proxy |\n| CCR Needle Retention | Lossless | 50 | **100%** | 77% | Exact Match |\n\nModel: `gpt-4o-mini` | Suite cost: ~$3 | Duration: ~15 min\n\n## Installation\n\n```bash\npip install \"headroom-ai[all]\"    # Everything including evals (recommended)\npip install \"headroom-ai[evals]\"  # Evaluation framework only\n```\n\n## Quick Start\n\n### Run the Evaluation Suite\n\n```bash\n# Quick smoke test (8 cases, ~10s)\npython -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n\n# Full Tier 1 suite (~$3, ~15 min) — requires proxy running\npython -m headroom.evals suite --tier 1 -o eval_results/\n\n# Extended suite (Tiers 1+2, ~$8, ~1 hr)\npython -m headroom.evals suite --tier 2 -o eval_results/\n\n# CI mode — exit 1 on any regression\npython -m headroom.evals suite --tier 1 --ci\n\n# List all available datasets\npython -m headroom.evals list\n```\n\n### Running with the Proxy (Recommended)\n\nFor the most accurate evaluation, run through the Headroom proxy which provides\nthe full stack: compression + CCR retrieval + cache alignment.\n\n```bash\n# Terminal 1: Start the proxy\nheadroom proxy --port 8787\n\n# Terminal 2: Run evals (auto-detects proxy)\npython -m headroom.evals suite --tier 1 -o eval_results/\n```\n\nWithout the proxy, the eval runner falls back to local compression only (no CCR).\n\n### Python API\n\n```python\nfrom headroom.evals.suite_runner import SuiteRunner\nfrom headroom.evals.reports.report_card import save_reports\n\n# Run Tier 1 suite\nrunner = SuiteRunner(model=\"gpt-4o-mini\", tiers=[1])\nresult = runner.run()\n\n# Save Markdown, JSON, and HTML reports\nsave_reports(result, \"eval_results/\")\n```\n\n## Session Probes (real recorded sessions)\n\nThe benchmark suites above prove the compressors in vitro. Session probes\nmeasure what compression removed from YOUR real sessions, offline and with no\nLLM or API key:\n\n```bash\n# 1. Record: run the proxy with recording enabled (opt-in; recordings contain\n#    full conversation content in plaintext and stay on this machine)\nHEADROOM_PROBE_RECORD_DIR=~/.headroom/probe-recordings headroom proxy start\n\n# 2. Use your agent through the proxy as normal, then score retention:\nheadroom evals probes --recordings ~/.headroom/probe-recordings\n```\n\nProbe targets are extracted from original tool results across three\ndimensions — exact numerics, artifact trail (paths/URLs/hashes), error\nevidence — and classified as retained (verbatim or surviving a format\nconversion), recoverable (behind a CCR retrieval marker), or lost. The report\nbuckets retention by compression ratio and groups it per transform. Use\n`--json-output report.json` for machine-readable results.\n\n## Evaluation Tiers\n\n### Tier 1: Core Report Card (~$3, ~15 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| GSM8K | lm-eval harness | Math reasoning accuracy |\n| TruthfulQA | lm-eval harness | Factual accuracy |\n| MMLU | lm-eval harness | 57-subject knowledge |\n| ARC-Challenge | lm-eval harness | Science reasoning |\n| HumanEval | lm-eval harness | Code generation |\n| SQuAD v2 | Before/After | Reading comprehension with compression |\n| BFCL | LLM-as-Judge | Function calling with compressed schemas |\n| Tool Outputs | Before/After + Proxy | Agent tool output compression |\n| CCR Needle Retention | Compression-only | Lossless anomaly preservation |\n\n### Tier 2: Extended (~$5 more, ~30 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HotpotQA | Before/After | Multi-hop QA with compressed passages |\n| MS MARCO | Before/After | RAG with compressed search results |\n| CodeSearchNet | Before/After | Code understanding after compression |\n| Info Retention | Compression-only | Probe fact survival in compressed output |\n\n### Tier 3: Deep Dive (~$9 more, ~45 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HellaSwag | lm-eval harness | Commonsense reasoning |\n| NarrativeQA | Before/After | Long narrative comprehension |\n| TriviaQA | Before/After | Factoid QA at scale |\n\n## Evaluation Methods\n\n### Before/After (Default)\n\nCompares LLM responses on original vs. compressed context:\n\n```\nOriginal Context ──► LLM ──► Response A\n                                         ├─► Compare (F1, semantic sim, GT match)\nCompressed Context ──► LLM ──► Response B\n```\n\nWhen the Headroom proxy is running, the \"compressed\" path goes through the full\nstack (compression + CCR tool injection + cache alignment), which is the real\nproduction experience.\n\n### LLM-as-Judge (for BFCL, tool use)\n\nUses an LLM judge to compare the compressed response against ground truth\nsemantically. This handles cases where the same correct answer can be expressed\nin different formats (function call JSON vs natural language computation).\n\n```\nCompressed Context ──► LLM ──► Response ──► LLM Judge ──► Score 1-5\n                                                  ▲\n                                          Ground Truth\n```\n\nScore >= 3 (\"partially correct or better\") = PASS. This means the compressed\ncontext preserved enough information for the LLM to reach the right answer.\n\n### Compression-Only (Zero Cost)\n\nTests compression quality without any LLM API calls:\n- **CCR Needle Retention**: Compress JSON arrays, verify errors/anomalies survive\n- **Information Retention**: Compress and check if probe facts are preserved\n\n## Available Datasets\n\n### RAG / Retrieval\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `hotpotqa` | Multi-hop QA over multiple Wikipedia passages | 100 |\n| `natural_questions` | Real Google search questions with Wikipedia answers | 100 |\n| `triviaqa` | Large-scale trivia QA with evidence documents | 100 |\n| `msmarco` | Real Bing search queries with relevant passages | 100 |\n| `squad` | SQuAD v2 reading comprehension | 100 |\n\n### Tool Use\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `bfcl` | Berkeley Function Calling Leaderboard | 100 |\n| `toolbench` | Real-world API tool usage scenarios | 100 |\n| `tool_outputs` | Built-in realistic tool outputs (JSON, logs, etc.) | 8 |\n\n### Long Context\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `longbench` | Long context understanding (4K-128K tokens) | 50 |\n| `narrativeqa` | Story comprehension | 100 |\n\n### Code\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `codesearchnet` | Code snippets with descriptions | 100 |\n| `humaneval` | Programming problems (OpenAI) | 164 |\n\n## Metrics\n\n| Metric | Description | Pass Threshold |\n|--------|-------------|----------------|\n| F1 Score | Token overlap between responses | > 0.7 |\n| Semantic Similarity | Embedding cosine similarity | > 0.85 |\n| Ground Truth Match | Answer present in response | True |\n| LLM Judge Score | 1-5 semantic correctness scale | >= 3 |\n| Accuracy Preserved | Any of the above passes | True |\n\n## CI/CD Integration\n\n```yaml\n# .github/workflows/eval.yml\nname: Evaluation Suite\n\non:\n  pull_request:\n    paths: ['headroom/transforms/**', 'headroom/evals/**']\n  schedule:\n    - cron: '0 6 * * 1'  # Weekly\n\njobs:\n  smoke-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with: { python-version: \"3.11\" }\n      - run: pip install -e \".[all]\"\n      - name: CCR Round-trip (zero cost)\n        run: |\n          python -c \"\n          from headroom.evals.runners.compression_only import CompressionOnlyRunner\n          r = CompressionOnlyRunner()\n          result = r.evaluate_ccr_lossless(r.generate_ccr_test_cases(50))\n          assert result.passed, f'CCR failures: {result.errors}'\n          print(f'CCR: {result.passed_cases}/{result.total_cases} PASS')\n          \"\n      - name: Quick eval\n        run: python -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n        env:\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n```\n\n## Environment Variables\n\nSet in `.env` at project root (auto-loaded by the suite runner):\n\n```\nOPENAI_API_KEY=sk-...      # Required for OpenAI models\nANTHROPIC_API_KEY=sk-ant-... # Required for Anthropic models\n```\n\n## Architecture\n\n```\nheadroom/evals/\n├── __init__.py              # Public API\n├── __main__.py              # CLI (quick, list, benchmark, suite, report)\n├── core.py                  # EvalCase, EvalResult, EvalSuite\n├── datasets.py              # 12 dataset loaders (HuggingFace + built-in)\n├── metrics.py               # F1, semantic similarity, ROUGE-L, BLEU\n├── cost_tracker.py          # API spend tracking + budget enforcement\n├── suite_runner.py          # Tiered suite orchestrator (16 benchmarks)\n├── comprehensive_benchmark.py  # EleutherAI lm-eval harness wrapper\n├── runners/\n│   ├── before_after.py      # Before/After + LLM-as-Judge + proxy support\n│   └── compression_only.py  # Zero-cost CCR + info retention evals\n├── reports/\n│   └── report_card.py       # Markdown, JSON, HTML report generation\n└── memory/\n    ├── judge.py             # LLM-as-judge (OpenAI, Anthropic, LiteLLM)\n    └── runner*.py           # Memory-specific evaluation\n```\n",".github/copilot-instructions.md":"When performing a pull request review in this repository:\r\n\r\n1. Treat `.github/PULL_REQUEST_TEMPLATE.md` and `CONTRIBUTING.md` as required policy, not optional guidance.\r\n2. Flag pull requests that do not include concrete \"Real Behavior Proof\" with environment, exact commands or steps, observed result, and what was not tested.\r\n3. Be strict about contributor verification: missing tests, missing runtime evidence, or placeholder PR text should be called out.\r\n4. For user-facing, release, dependency, workflow, or security-sensitive changes, prefer blocking feedback over optional suggestions.\r\n5. Focus on correctness, safety, and whether the PR is actually ready for human maintainer review.\r\n","plugins/headroom-oauth2/CHANGELOG.md":"# Changelog\n\n## 0.1.1\n\n- Inject the upstream bearer only on requests that go upstream. Local routes\n  (`/health`, `/stats*`, `/metrics`, `/v1/compress*`, `/ext/*`, …; see README)\n  are passed through untouched, so an unreachable IdP no longer 502s health\n  probes and management calls no longer mint tokens. `/p/<project>/` prefixes\n  are stripped first.\n- Startup log carries `scheme://host` of the token URL and the mint log a scope\n  count, instead of the full URL and scope list.\n- Requires `headroom-ai` ≥ 0.40 (extension middleware inside the proxy-token gate).\n\n## 0.1.0\n\nInitial release — generic OAuth2 client-credentials upstream-auth extension for the Headroom proxy.\n\n- Mints an OAuth2 client-credentials (RFC 6749 §4.4) bearer from a configurable token endpoint and\n  injects it as the upstream `Authorization` on each proxied request, via Headroom's opt-in\n  `headroom.proxy_extension` seam (`--proxy-extension oauth2`). No core changes; vendor-neutral.\n- `post` and `basic` client-auth styles; scopes, `audience`, RFC 8707 `resource`, static upstream\n  headers, configurable timeout/skew — all env-driven.\n- Token caching with single-flight refresh and pre-expiry skew; `expires_in` clamped to a positive\n  TTL.\n- Fails closed on misconfiguration; returns `502 upstream_auth_error` on mint failure without\n  leaking the IdP error body. `token_url` https-enforced (loopback exempt). Std-lib only (system\n  cert store -> works behind corporate SSL inspection).\n","plugins/headroom-snip/README.md":"# headroom-snip\n\nA Claude Code mod that shows what Headroom does to each request, live. When a\nrequest goes through the proxy, a pair of scissors runs along a bar the size of\nthe original prompt, cuts it down to what was actually sent, and the token\ncount drops as it goes:\n\n```\n✂ headroom 21k → 16k   tok ━━━━━━━━━━━━━━━━━━━━━━━✂⡀⠄⠂⠁⢀⠈⠐⠠ −81%\n✂ headroom 21k → 7.6k  tok ━━━━━━━━━━━✂⠈⠐⠠⡀⠄⠂⠁⢀⠈⠐⠠⡀⠄⠂······ −81%\n✂ headroom 21k → 4.1k  tok ━━━━━━·························· −81%\n  JSON crush ×2 · Kompress text · cache align   project 184k saved (62%) over 23 req ≈ 307 pages  details  hide\n```\n\n## What it shows\n\n- **The band above the prompt.** The latest request: original → sent tokens,\n  the snip animation, and the percentage cut. Below that, which compressors did\n  the cutting (`JSON crush`, `code AST`, `Kompress text`, `log squash`,\n  `cache align`, ...) and the running total since the session started. A request sent unchanged says why,\n  for example `kept: user message, recent code` or `nothing worth a snip`.\n- **`/headroom`.** Opens a pane with the requests since the session started: one bar per\n  request, what was cut and what was protected, how long compression took, the\n  biggest snip so far, and an all-time total.\n  `/headroom hide` and `/headroom show` toggle the band.\n- **The status line.** `✂ 184k tok saved · 62%`.\n- **Milestone toasts** at 10k, 50k, 100k, 250k, 500k, 1M and 5M tokens saved.\n- **No proxy?** If nothing answers, the band says so and suggests\n  `headroom wrap claude`.\n\n## How it works\n\nWhile a turn runs, the mod polls the proxy's loopback `GET /stats?cached=1`\nonce a second. It reads the `recent_requests` tail (per-request token counts\nand `transforms_applied`), and keeps polling for a few seconds after the turn\nends. Requests stamped before the session started count as history: they\naren't animated or added to the totals, even if the proxy only comes up later.\nNothing leaves your machine.\n\nThe proxy can't tell Claude Code sessions apart, so the totals are never\nper session. What they cover depends on how Claude Code reaches the proxy:\n\n- **Through `headroom wrap claude`:** each request carries an\n  `X-Headroom-Project` header naming the launch directory (its basename, so\n  two directories with the same name share a tag). The mod counts every\n  request with this session's tag, including other sessions in the same\n  project, and leaves other projects out. The proxy only reports tags for its\n  last ten requests, so a request it can't attribute is left out rather than\n  guessed. The band says \"project\" and `/headroom` names the project.\n- **Any other way:** there is no tag, so the totals cover every client on the\n  proxy since this session started. The band says \"proxy\" and `/headroom` says\n  so.\n\nIt finds the proxy in this order:\n\n1. `HEADROOM_PROXY_URL`\n2. `ANTHROPIC_BASE_URL` (as `headroom wrap claude` sets it)\n3. `http://127.0.0.1:8787`\n\nOnly loopback URLs are used: `http` or `https` on exactly `localhost`, `127.0.0.1`\nor `[::1]`, with no user or password. A value that isn't one (a remote proxy, or a\nhost like `localhost.example.com`) is skipped, so the mod never polls a remote host.\n\n## Install\n\n```bash\nclaude plugin marketplace add headroomlabs-ai/headroom\nclaude plugin install headroom-snip@headroom-marketplace\n```\n\nOr, from a checkout: `claude --plugin-dir plugins/headroom-snip`.\n\n## Develop\n\n```bash\nclaude plugin validate plugins/headroom-snip\nclaude plugin test plugins/headroom-snip      # tests/snip.test.tsx\ntsc -p plugins/headroom-snip                  # after Claude Code has loaded it once\n```\n\n`hooks/snip.ts` holds the pure parts (parsing, transform labels, the animation\nframes) and `hooks/register.tsx` holds the hooks and drawing.\n","wiki/ARCHITECTURE.md":"# Headroom SDK: A Complete Explanation\n\n## Architecture Overview\n\n```mermaid\nflowchart TB\n    subgraph Entry[\"Entry Points\"]\n        Proxy[\"Proxy Mode<br/><i>Zero code changes</i>\"]\n        SDK[\"SDK Mode<br/><i>HeadroomClient</i>\"]\n        Integrations[\"Integrations<br/><i>LangChain / Agno</i>\"]\n    end\n\n    subgraph Pipeline[\"Transform Pipeline\"]\n        direction TB\n\n        CA[\"Cache Aligner<br/>━━━━━━━━━━━━━━━<br/>Extracts dynamic content<br/>(dates, UUIDs, tokens)<br/>Stable prefix for caching\"]\n\n        SC[\"Smart Crusher<br/>━━━━━━━━━━━━━━━<br/>Analyzes tool outputs<br/>Keeps: first, last, errors, outliers<br/>70-95% reduction\"]\n\n        CM[\"Context Manager<br/>━━━━━━━━━━━━━━━<br/>Enforces token limits<br/>Scores by recency and relevance<br/>Fits context window\"]\n\n        CA --> SC --> CM\n    end\n\n    subgraph Cache[\"Provider Cache Optimization\"]\n        direction LR\n        Anthropic[\"Anthropic<br/><i>cache_control blocks</i><br/>90% savings\"]\n        OpenAI[\"OpenAI<br/><i>Prefix alignment</i><br/>50% savings\"]\n        Google[\"Google<br/><i>CachedContent API</i><br/>75% savings\"]\n    end\n\n    subgraph CCR[\"CCR: Compress-Cache-Retrieve\"]\n        Store[(\"Compression<br/>Store\")]\n        Tool[\"Retrieve Tool<br/><i>LLM requests original</i>\"]\n        Store <--> Tool\n    end\n\n    LLM[\"LLM API<br/><i>OpenAI / Anthropic / Google</i>\"]\n\n    Entry --> Pipeline\n    Pipeline --> Cache\n    Cache --> LLM\n    SC -.->|\"Stores original\"| Store\n    LLM -.->|\"If needed\"| Tool\n```\n\n---\n\n## What Problem Does Headroom Solve?\n\nWhen you use AI models like GPT-4 or Claude, you pay for **tokens** - the pieces of text you send (input) and receive (output). The problem is:\n\n1. **Tool outputs are HUGE**: When an AI agent calls tools (search, database queries, APIs), the responses are often massive JSON blobs with thousands of tokens\n2. **Most of that data is REDUNDANT**: 60 metric data points showing `cpu: 45%` repeated, or 50 log entries with the same error message\n3. **You're paying for waste**: Every token costs money and adds latency\n4. **Context windows fill up**: Models have limits (128K tokens), and bloated tool outputs eat into your available space\n\n**Headroom creates \"headroom\"** - it intelligently compresses your input tokens so you have more room (and budget) for what matters.\n\n---\n\n## How Headroom Works: The Big Picture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        YOUR APPLICATION                          │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      HEADROOM CLIENT                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │\n│  │   ANALYZE   │→ │  TRANSFORM  │→ │    CALL     │             │\n│  │  (Parser)   │  │  (Pipeline) │  │   (API)     │             │\n│  └─────────────┘  └─────────────┘  └─────────────┘             │\n│         │                │                │                     │\n│         ▼                ▼                ▼                     │\n│   Count tokens     Apply compressions   Send to OpenAI/Claude  │\n│   Detect waste     Preserve meaning     Log metrics            │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                    OPENAI / ANTHROPIC API                        │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Core Components (In Simple Terms)\n\n### 1. HeadroomClient (`client.py`) - The Wrapper\n\n`HeadroomClient` is still exported (`headroom/__init__.py:93,197`), but it is\nno longer the only SDK entry point: the site's current architecture\ndocumentation (`docs/content/docs/architecture.mdx`) describes SDK mode as\ncalling the one-function `compress()` API (`headroom.compress`,\n`headroom.CompressConfig`) directly on your messages, with `HeadroomClient`\nas the client-wrapping alternative. Both exist; this section covers only the\nwrapper.\n\nThis is what you interact with. It wraps your existing OpenAI or Anthropic client:\n\n```python\n# Before (normal OpenAI)\nclient = OpenAI(api_key=\"...\")\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n\n# After (with Headroom)\nbase = OpenAI(api_key=\"...\")\nclient = HeadroomClient(original_client=base, provider=OpenAIProvider())\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n```\n\n**What it does:**\n- Intercepts your API calls\n- Runs messages through the transform pipeline\n- Calls the real API with optimized messages\n- Logs metrics to a database\n- Returns the response unchanged\n\n**Two modes:**\n- `audit`: Just observe and log (no changes)\n- `optimize`: Apply transforms to reduce tokens\n\n---\n\n### 2. Providers (`providers/`) - Model-Specific Knowledge\n\nDifferent AI providers have different rules:\n\n```python\nclass OpenAIProvider:\n    # Knows GPT-4o has 128K context\n    # Knows how to count tokens (tiktoken)\n    # Knows pricing ($2.50 per million input tokens)\n\nclass AnthropicProvider:\n    # Knows Claude has 200K context\n    # Uses different tokenization (~4 chars per token)\n    # Different pricing structure\n```\n\n**Why this matters:** Token counting is model-specific. GPT-4 uses different tokenization than Claude. Headroom needs accurate counts to know how much to compress.\n\n---\n\n### 3. Parser (`parser.py`) - Understanding Your Messages\n\nBefore optimizing, Headroom needs to understand what's in your messages:\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are helpful...\"},\n    {\"role\": \"user\", \"content\": \"Search for X\"},\n    {\"role\": \"assistant\", \"tool_calls\": [...]},\n    {\"role\": \"tool\", \"content\": \"{huge JSON}\"},\n]\n\n# Parser breaks this into \"blocks\":\nblocks = [\n    Block(kind=\"system\", tokens=50, ...),\n    Block(kind=\"user\", tokens=10, ...),\n    Block(kind=\"tool_call\", tokens=20, ...),\n    Block(kind=\"tool_result\", tokens=5000, ...),  # ← This is the problem!\n]\n```\n\n**It also detects waste signals:**\n- Large JSON blobs (>500 tokens)\n- HTML tags and comments\n- Base64 encoded data\n- Excessive whitespace\n\n---\n\n### 4. Transforms (`transforms/`) - The Compression Magic\n\nThis is where the real work happens. Headroom has 4 transforms that run in sequence:\n\n#### Transform 1: Cache Aligner\n\n**Problem:** LLM providers cache your prompts, but only if they're byte-identical. If your system prompt has today's date, every day is a cache miss.\n\n```python\n# Before:\n\"You are helpful. Current Date: 2024-12-15\"  # Changes daily = no cache\n\n# After:\n\"You are helpful.\"  # Static = cacheable\n\"[Context: Current Date: 2024-12-15]\"  # Dynamic part moved to end\n```\n\n**How it works:**\n1. Find date patterns in system prompt\n2. Extract them\n3. Move to end of message\n4. Now the PREFIX is stable → cache hits!\n\n---\n\n#### Transform 2: Tool Crusher (Naive) - DISABLED BY DEFAULT\n\nThis was our first approach - simple but limited:\n\n```python\n# Before: 60 items\n[{\"ts\": 1, \"cpu\": 45}, {\"ts\": 2, \"cpu\": 45}, ..., {\"ts\": 60, \"cpu\": 95}]\n\n# After: First 10 items only\n[{\"ts\": 1, \"cpu\": 45}, ..., {\"ts\": 10, \"cpu\": 45}, {\"__truncated\": 50}]\n```\n\n**Problem:** If the important data (CPU spike) is at position 45, it gets thrown away!\n\n---\n\n#### Transform 3: Smart Crusher (NEW DEFAULT)\n\nThis is the intelligent approach using **statistical analysis**:\n\n```python\n# Analyzes the data first:\nanalysis = {\n    \"ts\": {\"type\": \"sequential\", \"unique_ratio\": 1.0},\n    \"host\": {\"type\": \"constant\", \"value\": \"prod-1\"},  # ← Same everywhere!\n    \"cpu\": {\"variance\": 892, \"change_points\": [45]},  # ← Spike detected!\n}\n\n# Smart compression:\n{\n    \"__headroom_constants\": {\"host\": \"prod-1\"},  # Factor out\n    \"__headroom_summary\": \"items 0-44: cpu stable at ~45\",  # Summarize boring part\n    \"data\": [\n        {\"ts\": 45, \"cpu\": 92},  # Keep the spike!\n        {\"ts\": 46, \"cpu\": 95},\n        ...,\n    ],\n}\n```\n\n**Strategies it uses:**\n1. **TIME_SERIES**: Detect variance spikes, keep change points\n2. **CLUSTER**: Group similar log messages, keep 1-2 per cluster\n3. **TOP_N**: For search results, keep highest scored\n4. **SMART_SAMPLE**: Statistical sampling with constant extraction\n\n---\n\n#### Transform 4: ML Compressor (Optional, Kompress)\n\n**When to use:** Maximum compression needed and latency is acceptable.\n\nThe proxy ships an opt-in ML compression path backed by **Kompress**\n(ModernBERT-based token classifier). Install with `pip install\n'headroom-ai[ml]'`; see `wiki/transforms.md` for current configuration.\n\n**Note:** The earlier LLMLingua-2 integration (`--llmlingua` flag, the\n`headroom-ai[llmlingua]` extra, and the `LLMLinguaCompressor` class) was\nretired and replaced by Kompress. `pip install 'headroom-ai[llmlingua]'`\nno longer resolves; use `[ml]` instead.\n\n---\n\n#### Context Management: Live-Zone-Only Compression\n\n**Approach:** Headroom never drops messages from conversation history, and it does not do position-based or score-based context management. Context management is handled automatically inside the pipeline by compressing only the **live zone** — the newest content blocks (the latest user message and the latest tool result / tool output).\n\n```\n# The cache hot zone is NEVER mutated:\n# - System prompt\n# - Tool definitions\n# - Older conversation turns\n#\n# Only the newest content blocks are compressed (type-aware),\n# and every compression is reversible via CCR.\n```\n\n**Why this matters:** Leaving the hot zone untouched preserves provider prompt caching (e.g. Claude's cached-prefix read discount). Because only the newest blocks change, earlier turns stay byte-stable across requests and keep hitting the KV cache. Compression is type-aware (handled by ContentRouter and its compressors) and fully reversible — the LLM can call `headroom_retrieve` to restore any compressed block.\n\n---\n\n### 5. Storage (`storage/`) - Metrics Database\n\nEvery request is logged:\n\n```sql\nCREATE TABLE requests (\n    id TEXT PRIMARY KEY,\n    timestamp TEXT,\n    model TEXT,\n    mode TEXT,  -- audit or optimize\n    tokens_input_before INTEGER,  -- Before Headroom\n    tokens_input_after INTEGER,   -- After Headroom\n    tokens_saved INTEGER,         -- The win!\n    transforms_applied TEXT,      -- What we did\n    ...\n);\n```\n\nThis lets you:\n- See how much you're saving\n- Generate reports\n- Track trends over time\n\n---\n\n## The Data Flow (Step by Step)\n\nLet's trace a real request:\n\n### Step 1: You call the API\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are an SRE. Date: 2024-12-15\"},\n        {\"role\": \"user\", \"content\": \"Check the metrics\"},\n        {\"role\": \"assistant\", \"tool_calls\": [...]},\n        {\"role\": \"tool\", \"content\": \"{60 metric points...}\"},  # 5000 tokens!\n        {\"role\": \"user\", \"content\": \"What's wrong?\"},\n    ],\n    headroom_mode=\"optimize\",\n)\n```\n\n### Step 2: HeadroomClient intercepts\n```python\n# In client.py:\ndef _create(self, messages, ...):\n    # 1. Parse messages into blocks\n    blocks, breakdown, waste = parse_messages(messages, tokenizer)\n    # breakdown = {\"system\": 50, \"user\": 20, \"tool_result\": 5000, ...}\n\n    # 2. Count original tokens\n    tokens_before = 5100\n```\n\n### Step 3: Transform Pipeline runs\n```python\n# In pipeline.py:\ndef apply(self, messages, ...):\n    # Transform 1: Cache Aligner\n    # - Extracts \"Date: 2024-12-15\" from system prompt\n    # - Moves to end\n\n    # Transform 2: Smart Crusher\n    # - Analyzes 60 metric points\n    # - Detects CPU spike at point 45\n    # - Compresses to 17 points (preserving spike)\n    # - Factors out constant \"host\" field\n\n    # Transform 3: Kompress ML compressor (opt-in via headroom-ai[ml])\n    # - ModernBERT-based compression on remaining long text\n    # - Auto-detects content type for optimal rate\n    # - Stores original in CCR for retrieval\n\n    # Transform 4: Rolling Window\n    # - Checks if we're under limit (we are)\n    # - No drops needed\n\n    return TransformResult(\n        messages=optimized,\n        tokens_before=5100,\n        tokens_after=1200,  # 76% reduction!\n        transforms=[\"cache_align\", \"smart_crush:1\"]\n    )\n```\n\n### Step 4: Call real API\n```python\n# In client.py:\nresponse = self._original.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=optimized_messages,  # Only 1200 tokens now!\n)\n```\n\n### Step 5: Log metrics and return\n```python\n# Save to database\nmetrics = RequestMetrics(\n    tokens_input_before=5100,\n    tokens_input_after=1200,\n    tokens_saved=3900,  # 76%!\n    ...\n)\nstorage.save(metrics)\n\nreturn response  # Unchanged from API\n```\n\n---\n\n## The Smart Crusher Deep Dive\n\nThis is the most sophisticated part. Here's how it analyzes data:\n\n### Field Analysis\n```python\ndef analyze_field(key, items):\n    values = [item[key] for item in items]\n\n    return {\n        \"unique_ratio\": len(set(values)) / len(values),\n        # 0.0 = all same (constant)\n        # 1.0 = all different (unique IDs)\n        \"variance\": statistics.variance(values),  # For numbers\n        # Low = stable\n        # High = changing\n        \"change_points\": detect_spikes(values),\n        # Indices where value jumps significantly\n    }\n```\n\n### Pattern Detection\n```python\ndef detect_pattern(field_stats):\n    # Has timestamp + numeric variance? → TIME_SERIES\n    if has_timestamp and has_numeric_variance:\n        return \"time_series\"\n\n    # Has message field + level field? → LOGS\n    if has_message_field and has_level_field:\n        return \"logs\"\n\n    # Has score/rank field? → SEARCH_RESULTS\n    if has_score_field:\n        return \"search_results\"\n\n    return \"generic\"\n```\n\n### Compression Strategy\n```python\ndef compress(items, analysis):\n    if analysis.pattern == \"time_series\":\n        # Keep points around change points\n        # Summarize stable regions\n        return time_series_compress(items, analysis.change_points)\n\n    elif analysis.pattern == \"logs\":\n        # Cluster similar messages\n        # Keep 1-2 per cluster\n        return cluster_compress(items, analysis.clusters)\n\n    elif analysis.pattern == \"search_results\":\n        # Sort by score\n        # Keep top N\n        return top_n_compress(items, analysis.score_field)\n```\n\n---\n\n## CCR Architecture: Compress-Cache-Retrieve\n\n### The Key Insight\n\n> \"Prefer raw > Compaction > Summarization only when compaction no longer yields enough space. Compaction (Reversible) strips out information that is redundant because it exists in the environment—if the agent needs to read the data later, it can use a tool to retrieve it.\" — Phil Schmid, Context Engineering\n\n**The problem with traditional compression:** If we guess wrong about what's important, we've permanently lost data. The LLM might need something we threw away.\n\n**CCR's solution:** Make compression **reversible**. When SmartCrusher compresses, the original data is cached. If the LLM needs more, it can retrieve instantly.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  TOOL OUTPUT (1000 items)                                         │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  HEADROOM CCR LAYER                                               │\n│                                                                   │\n│  1. COMPRESS: Keep 20 items (errors, anomalies, relevant)        │\n│  2. CACHE: Store full 1000 items in fast local cache             │\n│  3. INJECT: Add retrieval capability to LLM context              │\n│                                                                   │\n│  \"20 items shown. Use /v1/retrieve?hash=xxx for more.\"           │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  LLM PROCESSING                                                   │\n│                                                                   │\n│  Option A: LLM solves task with 20 items → Done                  │\n│  Option B: LLM needs more → retrieves via API                    │\n│            → We fetch from cache → Return instantly              │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  FEEDBACK LOOP                                                    │\n│                                                                   │\n│  Track: What did the LLM retrieve? What queries?                 │\n│  Learn: \"For this tool, keep items matching common queries\"      │\n│  Improve: Next compression uses learned patterns                 │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### CCR Phase 1: Compression Store\n\n**Location:** `headroom/cache/compression_store.py`\n\nWhen SmartCrusher compresses, the original content is stored for on-demand retrieval:\n\n```python\n@dataclass\nclass CompressionEntry:\n    hash: str  # 24-char SHA256 prefix for retrieval\n    original_content: str  # Full JSON before compression\n    compressed_content: str  # Compressed JSON\n    original_item_count: int\n    compressed_item_count: int\n    tool_name: str | None  # For feedback tracking\n    created_at: float\n    ttl: int = 1800  # 30 minute default (DEFAULT_CCR_TTL_SECONDS)\n```\n\n**Features:**\n- Thread-safe in-memory storage\n- TTL-based expiration (default 30 minutes; `DEFAULT_CCR_TTL_SECONDS`, override via `HEADROOM_CCR_TTL_SECONDS`)\n- LRU-style eviction when capacity reached\n- Hash-keyed retrieval that always returns the full original content\n\n**Usage:**\n```python\nstore = get_compression_store()\n\n# Store compressed content\nhash_key = store.store(\n    original=original_json,\n    compressed=compressed_json,\n    original_item_count=1000,\n    compressed_item_count=20,\n    tool_name=\"search_api\",\n)\n\n# Retrieve later (by hash; always returns the full original content)\nentry = store.retrieve(hash_key)\n```\n\n---\n\n### CCR Phase 2: Retrieval API\n\n**Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/retrieve` | POST | Retrieve original content by hash |\n| `/v1/retrieve/{hash}` | GET | Retrieve original content by hash |\n\nRetrieval is by hash only — it always returns the full original content.\n\n**Retrieval Request:**\n```json\n{\n    \"hash\": \"abc123def456...\"\n}\n```\n\n**Response:**\n```json\n{\n    \"hash\": \"abc123def456...\",\n    \"original_content\": \"[{...}, {...}, ...]\",\n    \"original_item_count\": 1000,\n    \"tool_name\": \"search_api\"\n}\n```\n\n---\n\n### CCR Phase 3: Tool Injection\n\nWhen compression happens, Headroom injects retrieval instructions into the LLM context.\n\n**Method A: System Message Injection**\n```\n## Compressed Context Available\nThe following tool outputs have been compressed. If you need more detail,\ncall the retrieve_compressed tool with the hash.\n\nAvailable: hash=abc123 (1000→20 items from search_api)\n```\n\n**Method B: MCP Tool Registration (Hybrid)**\nWhen running as MCP server, Headroom exposes retrieval as a tool:\n\n```json\n{\n    \"name\": \"headroom_retrieve\",\n    \"description\": \"Retrieve more items from compressed tool output\",\n    \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"hash\": {\"type\": \"string\"}\n        },\n        \"required\": [\"hash\"]\n    }\n}\n```\n\n**Marker Injection:**\nCompressed content includes retrieval markers:\n```json\n{\n    \"__headroom_compressed\": true,\n    \"__headroom_hash\": \"abc123def456\",\n    \"__headroom_stats\": {\n        \"original_items\": 1000,\n        \"kept_items\": 20,\n        \"errors_preserved\": 5\n    },\n    \"data\": [...]\n}\n```\n\n---\n\n### CCR Phase 4: Feedback Loop\n\n**Location:** `headroom/cache/compression_feedback.py`\n\nThe feedback system learns from retrieval patterns to improve future compression.\n\n**Tracked Patterns per Tool:**\n```python\n@dataclass\nclass ToolPattern:\n    tool_name: str\n    total_compressions: int  # Times we compressed this tool\n    total_retrievals: int  # Times LLM asked for more\n    full_retrievals: int  # Retrieved everything (all retrievals — hash-only)\n    search_retrievals: int  # Legacy; always 0 (retrieval is hash-only, no search)\n    common_queries: dict[str, int]  # Legacy query-pattern frequency (no longer populated)\n    queried_fields: dict[str, int]  # Legacy queried-field frequency (no longer populated)\n```\n\n**Key Metrics:**\n- **Retrieval Rate**: `total_retrievals / total_compressions`\n  - High (>50%) → Compressing too aggressively\n  - Low (<20%) → Compression is effective\n- **Full Retrieval Rate**: `full_retrievals / total_retrievals`\n  - High (>80%) → Data is unique, consider skipping compression\n\n**Compression Hints:**\n```python\n@dataclass\nclass CompressionHints:\n    max_items: int = 15  # Target item count\n    suggested_items: int | None  # Calculated optimal\n    skip_compression: bool  # Don't compress at all\n    preserve_fields: list[str]  # Always keep these fields\n    aggressiveness: float  # 0.0 = aggressive, 1.0 = conservative\n    reason: str  # Explanation\n```\n\n**Feedback-Driven Adjustment:**\n```python\n# In SmartCrusher._crush_array()\nif self.config.use_feedback_hints and tool_name:\n    feedback = get_compression_feedback()\n    hints = feedback.get_compression_hints(tool_name)\n\n    if hints.skip_compression:\n        return items, f\"skip:feedback({hints.reason})\", None\n\n    if hints.suggested_items is not None:\n        self.config.max_items_after_crush = hints.suggested_items\n```\n\n**Feedback Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/feedback` | GET | Get all learned patterns |\n| `/v1/feedback/{tool_name}` | GET | Get hints for specific tool |\n\n**Example Response:**\n```json\n{\n    \"total_compressions\": 150,\n    \"total_retrievals\": 23,\n    \"global_retrieval_rate\": 0.15,\n    \"tools_tracked\": 5,\n    \"tool_patterns\": {\n        \"search_api\": {\n            \"compressions\": 50,\n            \"retrievals\": 5,\n            \"retrieval_rate\": 0.10,\n            \"full_rate\": 0.20,\n            \"search_rate\": 0.80,\n            \"common_queries\": [\"status:error\", \"level:critical\"],\n            \"queried_fields\": [\"status\", \"level\", \"message\"]\n        }\n    }\n}\n```\n\n---\n\n### CCR Phase 5: Response Handler (Automatic Tool Call Handling)\n\n**Location:** `headroom/ccr/response_handler.py`\n\n**The Problem:** When the proxy injects the `headroom_retrieve` tool, the LLM might call it. But who handles that tool call? Without response handling, the tool call would go back to the client unhandled.\n\n**The Solution:** The Response Handler intercepts LLM responses, detects CCR tool calls, executes retrievals automatically, and continues the conversation until the LLM produces a final response.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  RESPONSE HANDLER FLOW                                           │\n│                                                                   │\n│  1. LLM Response arrives                                         │\n│     └─ Contains: tool_use(headroom_retrieve, hash=abc123)       │\n│                                                                   │\n│  2. Handler detects CCR tool call                                │\n│     └─ Extracts hash                                             │\n│                                                                   │\n│  3. Handler executes retrieval                                   │\n│     └─ By hash: store.retrieve(hash) → full original content    │\n│                                                                   │\n│  4. Handler continues conversation                               │\n│     └─ Adds tool result to messages                             │\n│     └─ Makes another API call                                   │\n│                                                                   │\n│  5. Repeat until no CCR tool calls                              │\n│     └─ Max 3 rounds (configurable)                              │\n│                                                                   │\n│  6. Return final response to client                             │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CCRToolCall:\n    tool_call_id: str  # For matching response\n    hash_key: str  # CCR hash to retrieve\n\n\n@dataclass\nclass CCRToolResult:\n    tool_call_id: str\n    content: str  # Retrieved data as JSON\n    success: bool\n    items_retrieved: int\n\n\nclass CCRResponseHandler:\n    async def handle_response(\n        self,\n        response: dict,  # Initial LLM response\n        messages: list,  # Conversation history\n        tools: list,  # Tool definitions\n        api_call_fn: Callable,  # Function to make API calls\n        provider: str,  # \"anthropic\" or \"openai\"\n    ) -> dict:\n        \"\"\"Handle CCR tool calls until final response.\"\"\"\n```\n\n**Streaming Support:**\n\nThe handler also supports streaming responses via `StreamingCCRHandler`:\n\n```python\nclass StreamingCCRBuffer:\n    \"\"\"Buffers streaming chunks to detect CCR tool calls.\"\"\"\n\n    chunks: list[bytes]\n    detected_ccr: bool\n\n\nclass StreamingCCRHandler:\n    \"\"\"Handles CCR in streaming responses.\"\"\"\n\n    async def process_stream(self, stream, messages, tools, api_call_fn):\n        \"\"\"Yields chunks, switching to buffered mode if CCR detected.\"\"\"\n```\n\n---\n\n### CCR Phase 6: Context Tracker (Multi-Turn Awareness)\n\n**Location:** `headroom/ccr/context_tracker.py`\n\n**The Problem:** In multi-turn conversations, earlier compressed data might become relevant later. Without tracking, the LLM has \"context amnesia\" - it can't reference data that was compressed in turn 1 when answering a question in turn 5.\n\n**The Solution:** The Context Tracker maintains awareness of all compressed content across the conversation and can proactively expand relevant data when a new query might need it.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  CONTEXT TRACKER FLOW                                            │\n│                                                                   │\n│  Turn 1: Search returns 100 files → compressed to 10            │\n│          Tracker stores: hash=abc123, sample=\"auth.py, db.py\"   │\n│                                                                   │\n│  Turn 5: User asks \"What about the authentication middleware?\"  │\n│          Tracker analyzes query:                                 │\n│          - \"authentication\" matches \"auth.py\" in sample         │\n│          - Relevance score: 0.7 (above threshold)               │\n│                                                                   │\n│  Proactive Expansion:                                           │\n│          - Retrieves abc123 before LLM responds                 │\n│          - Adds expanded context to request                     │\n│                                                                   │\n│  Result: LLM sees full file list, can answer accurately         │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CompressedContext:\n    hash_key: str              # CCR hash\n    turn_number: int           # When compression happened\n    timestamp: float           # For age-based filtering\n    tool_name: str | None      # Which tool was compressed\n    original_item_count: int\n    compressed_item_count: int\n    query_context: str         # User query at compression time\n    sample_content: str        # Preview for relevance matching\n\n@dataclass\nclass ExpansionRecommendation:\n    hash_key: str\n    reason: str                # Human-readable explanation\n    relevance_score: float     # 0-1, higher = more relevant\n    # Expansion always restores the full original content (retrieval is by hash).\n\nclass ContextTracker:\n    def track_compression(self, hash_key, turn_number, ...):\n        \"\"\"Track a compression event.\"\"\"\n\n    def analyze_query(self, query: str) -> list[ExpansionRecommendation]:\n        \"\"\"Find relevant compressed contexts for a query.\"\"\"\n\n    def execute_expansions(self, recommendations) -> list[dict]:\n        \"\"\"Execute recommended expansions.\"\"\"\n```\n\n**Relevance Calculation:**\n\nThe tracker uses simple but effective heuristics:\n\n1. **Keyword overlap with sample content** - Extract keywords from query, match against compressed content preview\n2. **Keyword overlap with original query** - Match against the query that triggered compression\n3. **Tool name relevance** - File operations more likely to need expansion for \"file\", \"where\", \"find\" queries\n4. **Age discount** - Older contexts get lower scores\n\n**Configuration:**\n\n```python\n@dataclass\nclass ContextTrackerConfig:\n    enabled: bool = True\n    max_tracked_contexts: int = 100  # LRU eviction\n    relevance_threshold: float = 0.3  # Min score to recommend\n    max_context_age_seconds: float = 300  # 5 minutes\n    proactive_expansion: bool = True\n    max_proactive_expansions: int = 2  # Per query\n```\n\n---\n\n### Why CCR is a Moat\n\n1. **Reversible**: No permanent information loss. Worst case = retrieve everything.\n2. **Transparent**: LLM knows it can ask for more data.\n3. **Automatic**: Response Handler executes retrievals without client intervention.\n4. **Context-Aware**: Context Tracker prevents multi-turn amnesia.\n5. **Feedback Loop**: Learn from actual needs, not guesses.\n6. **Network Effect**: Retrieval patterns across users improve compression for everyone.\n7. **Zero-Risk**: If compression fails, instant fallback to original data.\n\n---\n\n## Image Compression Architecture\n\nVision models charge by the token, and images are expensive (765-2900 tokens for a typical image). Headroom's image compression uses a **trained ML router** to automatically select the optimal compression technique.\n\n### The Key Insight\n\nNot all image queries need full resolution:\n- \"What is this?\" → Low detail is fine (87% savings)\n- \"Count the whiskers\" → Need full detail (0% savings)\n- \"Read the sign\" → Could convert to text (99% savings)\n\n### How It Works\n\n```\nUser: [image] + \"What animal is this?\"\n           ↓\n┌─────────────────────────────────┐\n│  1. Query Analysis              │\n│  TrainedRouter (MiniLM)         │\n│  Classifies → full_low          │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  2. Image Analysis (Optional)   │\n│  SigLIP checks:                 │\n│  - Has text? Is complex?        │\n│  - Fine details needed?         │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  3. Apply Compression           │\n│  OpenAI: detail=\"low\"           │\n│  Anthropic: Resize to 512px     │\n│  Google: Resize to 768px        │\n└─────────────────────────────────┘\n           ↓\nCompressed request → LLM → Response\n```\n\n### The Trained Router\n\nA fine-tuned MiniLM classifier hosted on HuggingFace:\n\n- **Model**: `chopratejas/technique-router`\n- **Size**: ~128MB (downloaded once, cached)\n- **Accuracy**: 93.7% on 1,157 training examples\n- **Latency**: ~10ms CPU, ~2ms GPU\n\nThe router learns from examples like:\n| Query | Technique |\n|-------|-----------|\n| \"What is this?\" | `full_low` |\n| \"Count the items\" | `preserve` |\n| \"Read the text\" | `transcode` |\n| \"What's in the corner?\" | `crop` |\n\n### Provider-Specific Compression\n\nEach provider handles images differently:\n\n| Provider | Method | Savings |\n|----------|--------|---------|\n| **OpenAI** | `detail=\"low\"` parameter | ~87% |\n| **Anthropic** | PIL resize to 512px | ~75% |\n| **Google** | PIL resize to 768px (tile-optimized) | ~75% |\n\n### Integration Points\n\nImage compression runs in the proxy **before** text compression:\n\n```\nRequest arrives\n      ↓\n[Image Compression] ← NEW\n      ↓\n[Transform Pipeline: Cache Aligner → Smart Crusher → ...]\n      ↓\nForward to LLM\n```\n\nThis ensures images are compressed first, then text compression (CCR, SmartCrusher) handles the rest.\n\n### Code Location\n\n```\nheadroom/\n├── image/\n│   ├── __init__.py         # Public API\n│   ├── compressor.py       # ImageCompressor class\n│   └── trained_router.py   # TrainedRouter (HuggingFace model)\n├── proxy/\n│   └── server.py           # Integration point\n```\n\n---\n\n## File Structure Explained\n\n```\nheadroom/\n├── __init__.py          # Public exports\n├── client.py            # HeadroomClient - the main wrapper\n├── config.py            # All configuration dataclasses\n├── parser.py            # Message → Block decomposition\n├── tokenizer.py         # Token counting abstraction\n├── utils.py             # Hashing, markers, helpers\n│\n├── providers/\n│   ├── base.py          # Provider/TokenCounter protocols\n│   ├── openai.py        # OpenAI-specific (tiktoken)\n│   └── anthropic.py     # Anthropic-specific\n│\n├── transforms/\n│   ├── base.py              # Transform protocol\n│   ├── pipeline.py          # Orchestrates all transforms\n│   ├── cache_aligner.py     # Date extraction for caching\n│   ├── smart_crusher.py     # Statistical compression (default)\n│   ├── code_compressor.py   # AST-aware code compression (tree-sitter)\n│   └── (legacy llmlingua_compressor.py removed — see [ml] extra for Kompress;\n│        rolling_window.py / intelligent_context.py / scoring.py / tool_crusher.py\n│        removed — context management is now live-zone-only)\n│\n├── cache/               # CCR Architecture - Caching & Storage\n│   ├── compression_store.py    # Phase 1: Store original content\n│   ├── compression_feedback.py # Phase 4: Learn from retrievals\n│   ├── anthropic.py     # Anthropic cache optimizer\n│   ├── openai.py        # OpenAI cache optimizer\n│   ├── google.py        # Google cache optimizer\n│   └── dynamic_detector.py # Dynamic content detection\n│\n├── ccr/                 # CCR Architecture - Tool Injection & Response Handling\n│   ├── __init__.py             # CCR module exports\n│   ├── tool_injection.py       # Phase 3: Inject retrieval tool\n│   ├── response_handler.py     # Phase 5: Handle CCR tool calls\n│   ├── context_tracker.py      # Phase 6: Multi-turn context tracking\n│   └── mcp_server.py           # MCP server for retrieval tool\n│\n├── relevance/           # Relevance scoring for compression\n│   ├── bm25.py          # BM25 keyword scorer\n│   ├── embedding.py     # Semantic embedding scorer\n│   └── hybrid.py        # Adaptive fusion scorer\n│\n├── storage/\n│   ├── base.py          # Storage protocol\n│   ├── sqlite.py        # SQLite implementation\n│   └── jsonl.py         # JSON Lines implementation\n│\n├── proxy/\n│   └── server.py        # Production HTTP proxy (CCR endpoints)\n│\n└── reporting/\n    └── generator.py     # HTML report generation\n```\n\n---\n\n## Key Design Decisions\n\n### 1. Provider-Agnostic\nWorks with ANY OpenAI-compatible API:\n- OpenAI\n- Azure OpenAI\n- Anthropic\n- Groq\n- Together\n- Local models (Ollama)\n\n### 2. Deterministic Transforms\nNo LLM calls for compression. Everything is:\n- Statistical analysis\n- Pattern matching\n- Rule-based\n\nThis means:\n- Predictable results\n- Fast (<10ms overhead)\n- No added API costs\n\n### 3. Safety First\n- Never modify user/assistant TEXT content\n- Tool call + response are atomic (drop both or neither)\n- Parse failures = no-op (return unchanged)\n- Audit mode for testing before optimizing\n\n### 4. Smart by Default\n- SmartCrusher enabled (statistical, content-aware analysis — not naive rules)\n- Conservative settings that preserve important data\n\n---\n\n## What Makes This Different?\n\n### vs. Summarization (LLM-based compression)\n| Headroom | Summarization |\n|----------|---------------|\n| Deterministic | Non-deterministic |\n| ~10ms overhead | ~2-5 seconds overhead |\n| No extra API cost | Costs money to summarize |\n| Preserves structure | Loses structure |\n| Can't hallucinate | Can hallucinate |\n\n### vs. Simple Truncation\n| Headroom | Truncation |\n|----------|------------|\n| Keeps important data | Loses end of data |\n| Statistical analysis | No analysis |\n| Detects spikes | Misses spikes |\n| Factors out constants | Keeps redundancy |\n\n---\n\n## The Numbers (From Our Tests)\n\n> **Audit note (2026-09-02):** the specific token counts previously shown here\n> (a \"5 tool call SRE incident\" example) could not be traced to any benchmark,\n> test, or committed artifact in this repo and have been removed rather than\n> replaced with another unverified figure. For sourced compression numbers see\n> [Benchmarks](benchmarks.md) / `docs/content/docs/benchmarks.mdx`.\n\nReal-world SRE incident investigation (metrics, logs, status, deployments,\nrunbook tool calls in one turn) is the kind of workload SmartCrusher targets:\nstatistical, repetitive tool output where most of the redundancy is in\nconstant fields and stable regions, not in the handful of data points (spikes,\nerrors) that actually matter to the model's answer.\n\nThe model could still:\n- Identify the CPU spike (preserved by change point detection)\n- Reference specific error rates (kept in compressed data)\n- Provide correct remediation commands\n\n---\n\n## Summary\n\n**Headroom is a Context Budget Controller that:**\n\n1. **Wraps** your existing LLM client\n2. **Analyzes** your messages to find waste\n3. **Compresses** tool outputs intelligently (not blindly)\n4. **Preserves** important information (spikes, anomalies, unique data)\n5. **Logs** everything for observability\n6. **Saves** 70-90% of tokens on tool-heavy workloads\n\n**The key insight:** Most tool output redundancy is **statistical** (repeated values, constant fields, similar messages). By analyzing the data first, we can compress intelligently without losing the information that matters.\n","plugins/headroom-oauth2/README.md":"# headroom-oauth2\n\nGeneric **OAuth2 client-credentials** upstream-auth extension for the\n[Headroom](https://github.com/headroomlabs-ai/headroom) proxy.\n\nWhen Headroom routes to an OpenAI-compatible backend that is protected by an\nOAuth2 client-credentials flow (enterprise AI gateways, Azure AD / Entra, Okta,\nAuth0, Keycloak, Cognito, …), this extension mints a bearer token from a\nconfigurable token endpoint, caches + refreshes it (single-flight), and injects\n`Authorization: Bearer <token>` on each upstream request. Optional static upstream\nheaders are sent via litellm. **Fully vendor-neutral — no provider is hard-coded.**\n\nIt plugs into Headroom's public `headroom.proxy_extension` entry-point seam, so it\nis fully out-of-tree and opt-in.\n\n## Install & enable\n```bash\npip install headroom-oauth2\nheadroom proxy --backend litellm-openai --proxy-extension oauth2\n```\n\n## Configure (env; no-op unless HEADROOM_OAUTH2_TOKEN_URL is set)\n| Env | Meaning |\n|-----|---------|\n| `HEADROOM_OAUTH2_TOKEN_URL` | token endpoint (client_credentials grant) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | credentials (secrets) |\n| `HEADROOM_OAUTH2_SCOPES` | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | optional audience |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | static upstream headers, `K=V,K2=V2` |\n\nTokens are minted with the standard library (`urllib`, system cert store), which\nworks behind corporate SSL-inspection where bundled-root TLS stacks fail.\n\n\n**Effective backends:** the injected bearer reaches the upstream only for OpenAI-compatible /\npassthrough litellm providers. `bedrock` / `vertex` / `sagemaker` authenticate from env and\nignore it, so this extension is a no-op there (it logs a warning at startup).\n\n**Transport:** `token_url` must be `https` (loopback `http` is allowed for tests; set\n`HEADROOM_OAUTH2_ALLOW_INSECURE=1` to override). Tokens are minted with the standard library\n(`urllib`, system cert store), so a corporate-injected CA is trusted without bundling roots.\n\n## What gets the upstream bearer\n\nThe minted token is injected only on requests that **go upstream**. Routes the\nproxy answers itself — `/health`, `/livez`, `/readyz`, `/stats*`, `/metrics`,\n`/quota`, `/settings*`, `/dashboard*`, `/admin/*`, `/debug/*`, `/v1/compress*`,\n`/v1/usage`, `/v1/retrieve*`, `/v1/telemetry*`, `/v1/toin*`, `/v1/feedback*`,\nand any extension route under `/ext/` — are passed through untouched, so an\nunreachable IdP never turns a health probe into a 502 and management calls never\ncost a token mint. A `/p/<project>/` base-URL prefix is stripped before the\ncheck.\n\nRequires `headroom-ai` ≥ 0.40, where extension middleware runs inside the\nproxy's `HEADROOM_PROXY_TOKEN` gate: clients may then authenticate with\n`Authorization: Bearer <proxy token>` and the gate checks it before this\nextension replaces it with the upstream bearer.\n","plugins/headroom-agent-hooks/README.md":"# Headroom agent hooks\r\n\r\nThis plugin exposes lightweight startup hooks for Claude Code and GitHub Copilot CLI.\r\n\r\nThe hooks resolve and call:\n\r\n```bash\r\nheadroom init hook ensure\r\n```\r\n\r\nThat hidden helper checks for a matching durable `headroom init` deployment and starts it if needed.\n\nWhen `CLAUDE_PLUGIN_ROOT` points to a readable launcher, resolution order is\n`HEADROOM_BIN`, `headroom` on `PATH`, then `headroom` and\n`headroom.exe` in `$HOME/.local/bin`, `$HOME/.local/share/uv/tools/headroom-ai/bin`,\n`${PIPX_HOME:-$HOME/.local/pipx}/venvs/headroom-ai/bin`, `/opt/homebrew/bin`, and\n`/usr/local/bin`. If no executable is found, `HEADROOM_PYTHON`, `python3`, and\n`python` are checked for an importable `headroom` module and invoked as\n`python -m headroom.cli init hook ensure`.\n\nSet `HEADROOM_BIN` or `HEADROOM_PYTHON` to override discovery. An absent CLI emits\none actionable diagnostic and exits successfully, so the host hook remains\nnonblocking. Without a readable launcher, the hook runs bare\n`headroom init hook ensure` from `PATH` with none of the discovery above. Copilot\nCLI on Windows uses the manifest's `powershell` entry, which does the same.\n","plugins/headroom-oauth2/SPEC.md":"# Spec — `headroom-oauth2` (generic OAuth2 client-credentials upstream auth)\n\n## Summary\n\nA vendor-neutral proxy extension (registers on Headroom's `headroom.proxy_extension` seam) that\nmints an OAuth2 **client-credentials** (RFC 6749 §4.4) bearer from a configured token endpoint and\ninjects it as the upstream `Authorization` on every proxied request. Lets Headroom front any\ngateway that requires a minted machine token (not a static API key) — with **zero core changes**\nand **no vendor specifics** (the gateway is entirely config/env).\n\nIt complements `#510` (env-var auth), which assumes a long-lived static key; this covers the\n\"mint-then-refresh a short-lived token\" case.\n\n## API surface (config / CLI / env)\n\nOpt-in only, via Headroom's existing flags — **no new CLI flags**:\n\n    headroom proxy --backend litellm-openai --proxy-extension oauth2\n    # or HEADROOM_PROXY_EXTENSIONS=oauth2\n\nAll configuration is env (12-factor; nothing baked in):\n\n| Env var | Required | Meaning |\n|---|---|---|\n| `HEADROOM_OAUTH2_TOKEN_URL` | yes (else no-op) | OAuth2 token endpoint; must be `https` (loopback `http` allowed for tests) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | yes | client credentials |\n| `HEADROOM_OAUTH2_SCOPES` | no | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | no | `audience` form param |\n| `HEADROOM_OAUTH2_RESOURCE` | no | RFC 8707 target `resource` form param |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | no | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | no | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | no | static upstream headers, `K=V,K2=V2` (control chars rejected) |\n| `HEADROOM_OAUTH2_TIMEOUT` / `_SKEW` | no | token request timeout / pre-expiry refresh skew (s) |\n| `HEADROOM_OAUTH2_ALLOW_INSECURE` | no | `1` to allow a non-loopback `http` token_url (discouraged) |\n\nPublic Python API: `OAuth2ClientCredentials`, `OAuth2Middleware`, `OAuth2Error`, `install`,\n`provider_from_env`, `parse_headers`.\n\n## Changes to existing behavior / defaults / compatibility\n\n- **None unless explicitly enabled.** The entry point is dormant until `--proxy-extension oauth2`\n  is passed, and even then a **no-op** unless `HEADROOM_OAUTH2_TOKEN_URL` is set.\n- When active, it **overwrites the request `Authorization` header** with the minted bearer before\n  the backend runs. The client's own `Authorization`/`x-api-key` is intentionally replaced (the\n  proxy authenticates to the gateway on the client's behalf). *Compatibility note:* because the\n  request then carries a bearer, Headroom classifies it as OAuth-mode auth — same as supplying a\n  bearer yourself; no new classification path.\n- No change to defaults, the request/response body, model routing, or compression.\n\n## User stories (Given / When / Then)\n\n- **Golden path** — *Given* a proxy started with `--proxy-extension oauth2` and valid\n  `TOKEN_URL`/`CLIENT_ID`/`CLIENT_SECRET`, *When* a client sends `/v1/messages`, *Then* the\n  extension mints (or reuses a cached) bearer and the upstream receives `Authorization: Bearer\n  <minted>` plus any static headers; the client never sees the secret.\n- **Edge: token endpoint down** — *Given* an unreachable/erroring `TOKEN_URL`, *When* a request\n  arrives, *Then* the proxy returns `502 upstream_auth_error` (no upstream call, no secret/body\n  leak) and stays up; the next request retries.\n- **Edge: wrong backend** — *Given* `--backend bedrock` (env-auth), *When* the extension installs,\n  *Then* it logs a loud warning that the injected bearer will have no effect and to use an\n  OpenAI-compatible/passthrough backend.\n\n## Failure modes & recovery\n\n| Failure | Behavior |\n|---|---|\n| Missing/invalid config at startup | `install()` raises -> proxy **fails closed** (won't start mis-auth'd) |\n| Token endpoint unreachable / non-2xx / non-JSON / no `access_token` | `OAuth2Error` -> `502`, per-request, proxy stays up, retried next request |\n| `expires_in` = 0/negative/absent | clamped to a positive TTL (never stale, never per-request mint) |\n| Concurrent first requests | single-flight lock -> exactly one mint per refresh |\n| Malformed `HEADROOM_OAUTH2_HEADERS` (CR/LF) | offending pair dropped with a warning (no header injection) |\n\n## Resilience (Docker / native / wrappers / providers / multi-process)\n\n- **Native & Docker:** identical; pure env-driven, std-lib only. Token minted via `urllib` against\n  the **system cert store**, so a corporate-injected CA is trusted with no bundled roots (works in\n  SSL-inspection networks).\n- **Wrappers (`headroom wrap`, agent hooks):** the extension lives at the proxy layer, so anything\n  routed through the proxy inherits it transparently.\n- **Providers:** effective for OpenAI-compatible / passthrough litellm backends (those that forward\n  the request bearer upstream). `bedrock`/`vertex`/`sagemaker` authenticate from env and ignore the\n  bearer -> the extension warns and is a no-op there.\n- **Multi-process (multiple workers):** the token cache is per-process; each worker mints/refreshes\n  independently. Acceptable for client-credentials (idempotent, low rate); no shared state, no\n  cross-process lock needed. Documented so operators can size token-endpoint rate limits.\n\n## Security & privacy\n\n- Secrets are env-only; **never logged** and **never returned** to the client.\n- The IdP error body is **drained, not surfaced** (may echo sensitive context).\n- `token_url` is **https-enforced** (loopback exception for tests; explicit opt-out env).\n- The minted bearer is sent only to the configured upstream; the client's inbound credential is\n  replaced, not forwarded onward.\n\n## Observability / logging / telemetry\n\n- `INFO` on install (token_url + auth style, no secrets) and on each mint (`ttl`, scopes).\n- `WARNING` on mint failure, env-auth-backend no-op, and dropped malformed static headers.\n- No metrics/telemetry emitted; piggybacks on Headroom's existing request logging. (A future\n  counter for mint/refresh/failure could be added if maintainers want it.)\n\n## Rollback / migration\n\n- **No migration** — additive and opt-in; existing deployments are unaffected.\n- **Instant rollback:** drop `--proxy-extension oauth2` (or unset `HEADROOM_PROXY_EXTENSIONS`), or\n  uninstall the package. No state to clean up, no config format changes.\n\n## Dependencies\n\n- **Runtime:** standard library only (no new core dependency). `litellm` is touched **only** if\n  `HEADROOM_OAUTH2_HEADERS` is set, and it is already a Headroom backend dependency — declared here\n  as the optional `[litellm]` extra, not a hard requirement.\n","plugins/headroom-snip/tsconfig.json":"# Headroom-snip Skill\n\nPath: `plugins/headroom-snip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/tsconfig.json)","plugins/hermes/README.md":"# hermes Documentation\n\nPath: `plugins/hermes/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/README.md)","plugins/openclaw/README.md":"# openclaw Documentation\n\nPath: `plugins/openclaw/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/README.md)","plugins/openclaw/openclaw.plugin.json":"# openclaw Plugin Manifest\n\nPath: `plugins/openclaw/openclaw.plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/openclaw.plugin.json)","plugins/openclaw/package-lock.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package-lock.json)","plugins/openclaw/package.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package.json)","plugins/openclaw/tsconfig.json":"# Openclaw Skill\n\nPath: `plugins/openclaw/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/tsconfig.json)","plugins/opencode/README.md":"# opencode Documentation\n\nPath: `plugins/opencode/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/README.md)","plugins/opencode/package-lock.json":"# Opencode Skill\n\nPath: `plugins/opencode/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package-lock.json)","plugins/opencode/package.json":"# Opencode Skill\n\nPath: `plugins/opencode/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package.json)","plugins/opencode/tsconfig.json":"# Opencode Skill\n\nPath: `plugins/opencode/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/tsconfig.json)","e2e/wrap/tools/README.md":"# tools Documentation\n\nPath: `e2e/wrap/tools/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/README.md)","e2e/wrap/tools/package-lock.json":"# Tools Skill\n\nPath: `e2e/wrap/tools/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package-lock.json)","e2e/wrap/tools/package.json":"# Tools Skill\n\nPath: `e2e/wrap/tools/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package.json)","plugins/headroom-agent-hooks/.claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.claude-plugin/plugin.json)","plugins/headroom-agent-hooks/hooks/hooks.json":"# Hooks Skill\n\nPath: `plugins/headroom-agent-hooks/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/hooks/hooks.json)","plugins/headroom-snip/.claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-snip/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/.claude-plugin/plugin.json)","plugins/headroom-snip/hooks/hooks.json":"# Hooks Skill\n\nPath: `plugins/headroom-snip/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/hooks/hooks.json)","plugins/hermes/headroom_retrieve/plugin.yaml":"# Headroom_retrieve Skill\n\nPath: `plugins/hermes/headroom_retrieve/plugin.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/headroom_retrieve/plugin.yaml)","plugins/openclaw/hook-shim/HOOK.md":"# Hook-shim Skill\n\nPath: `plugins/openclaw/hook-shim/HOOK.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/hook-shim/HOOK.md)","plugins/headroom-agent-hooks/.github/plugin/plugin.json":"# plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.github/plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.github/plugin/plugin.json)"},"items":[{"name":"llms.txt","path":"llms.txt","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/llms.txt","title":"LLM Index & Context Digest","category":"root-instruction","format":"text","content":"# Headroom\n\n> Context optimization layer for LLM applications. Compress tool outputs, logs, files, and RAG chunks before they reach the model. Same answers, 60–95% fewer tokens. Library, proxy, and MCP server. Apache 2.0, local-first.\n\nHeadroom is shipped as a Python package (`headroom-ai`), a TypeScript package (`headroom-ai`), an OpenAI + Anthropic-compatible HTTP proxy (`headroom proxy`), and an MCP server (`headroom_compress`, `headroom_retrieve`, `headroom_stats` tools). All four modes use the same compression pipeline: per-content-type compressors (JSON, code, logs, diffs, text) feed into a Compress-Cache-Retrieve (CCR) store so compression stays reversible — the LLM can ask for the original whenever it wants.\n\nThe canonical, always-current documentation index lives at the docs site below. If you can fetch one URL, fetch that one; the entries here are a hand-curated subset.\n\n## Canonical docs (start here)\n\n- [Live llms.txt (full doc index)](https://docs.headroomlabs.ai/llms.txt): Auto-generated index of every doc page with descriptions.\n- [Live llms-full.txt (every doc page concatenated)](https://docs.headroomlabs.ai/llms-full.txt): One Markdown blob containing every doc page. Use when you can spend the tokens for full context.\n- [Docs site](https://docs.headroomlabs.ai/docs): Human-browsable docs with search.\n- [GitHub repo](https://github.com/headroomlabs-ai/headroom): Source, issues, releases.\n- [PyPI package](https://pypi.org/project/headroom-ai/): Python install.\n- [npm package](https://www.npmjs.com/package/headroom-ai): TypeScript install.\n\n## Install (copy-paste-runnable)\n\n- Python: `pip install headroom-ai` (add `[all]` for every optional extra)\n- TypeScript / Node: `npm install headroom-ai` (or `pnpm add headroom-ai`, `bun add headroom-ai`)\n- Docker local: `docker run --rm -p 127.0.0.1:8787:8787 ghcr.io/headroomlabs-ai/headroom:latest --host 0.0.0.0`\n- Run the proxy: `headroom proxy --port 8787` then point any client at `http://127.0.0.1:8787`\n- Wrap an agent in one command: `headroom wrap claude` (also: `codex`, `copilot`, `cursor`, `aider`, `opencode`, `cline`, `continue`, `goose`, `openhands`, `openclaw`, `vibe`, `omp`)\n\n## Entry points\n\n- [Quickstart](https://docs.headroomlabs.ai/docs/quickstart): 5-minute end-to-end (install → compress → call the model).\n- [Installation](https://docs.headroomlabs.ai/docs/installation): All install paths, extras, Docker tags, env vars.\n- [Proxy server](https://docs.headroomlabs.ai/docs/proxy): Run as a local HTTP proxy in front of OpenAI / Anthropic / Gemini.\n- [MCP server](https://docs.headroomlabs.ai/docs/mcp): `headroom_compress`, `headroom_retrieve`, `headroom_stats` for Claude Code / Cursor / any MCP host.\n- [API reference](https://docs.headroomlabs.ai/docs/api-reference): Python + TypeScript `compress()` API.\n\n## How it works\n\n- [How compression works](https://docs.headroomlabs.ai/docs/how-compression-works): Three-stage pipeline + automatic content routing.\n- [SmartCrusher](https://docs.headroomlabs.ai/docs/smart-crusher): Statistical JSON / array compression (70–90% on tool outputs).\n- [Code compression](https://docs.headroomlabs.ai/docs/code-compression): AST-aware via tree-sitter (preserves imports, signatures, types).\n- [Text & log compression](https://docs.headroomlabs.ai/docs/text-and-logs): Search results, build logs, diffs.\n- [CCR (reversible)](https://docs.headroomlabs.ai/docs/ccr): Compress-Cache-Retrieve — originals never deleted; LLM retrieves on demand.\n\n## SDK / framework integrations\n\n- [Anthropic SDK](https://docs.headroomlabs.ai/docs/anthropic-sdk): `withHeadroom(anthropic)` wrapper.\n- [OpenAI SDK](https://docs.headroomlabs.ai/docs/openai-sdk): `withHeadroom(openai)` wrapper.\n- [Vercel AI SDK](https://docs.headroomlabs.ai/docs/vercel-ai-sdk): Middleware + `withHeadroom()`.\n- [LangChain](https://docs.headroomlabs.ai/docs/langchain): Chat models, memory, retrievers, agents.\n- [Agno](https://docs.headroomlabs.ai/docs/agno): Model wrapping + observability hooks.\n- [Strands](https://docs.headroomlabs.ai/docs/strands): Model wrapping + hook-based tool output compression.\n- [LiteLLM](https://docs.headroomlabs.ai/docs/litellm): Single callback; works with all 100+ LiteLLM providers.\n\n## Memory & cross-agent state\n\n- [Persistent memory](https://docs.headroomlabs.ai/docs/memory): Per-project SQLite + HNSW vector store. No cross-project bleed (GH #462).\n- [SharedContext](https://docs.headroomlabs.ai/docs/shared-context): Compressed inter-agent context handoffs.\n- [Failure learning](https://docs.headroomlabs.ai/docs/failure-learning): Offline analysis writes corrections to `CLAUDE.local.md` (default, gitignored) or `CLAUDE.md` (shared) / `AGENTS.md` / `GEMINI.md`.\n\n## Operations\n\n- [Configuration](https://docs.headroomlabs.ai/docs/configuration): Env vars, config file, per-call overrides.\n- [Benchmarks](https://docs.headroomlabs.ai/docs/benchmarks): Token-savings numbers across content types.\n- [Troubleshooting](https://docs.headroomlabs.ai/docs/troubleshooting): Common failure modes and fixes.\n- [Limitations](https://docs.headroomlabs.ai/docs/limitations): What Headroom won't do well today.\n\n## Headroom for Teams\n\nFor teams and companies that want Headroom across every developer rather than one laptop: Headroom Enterprise adds more savings (tool search for every model, harness tuning, extra compressors), automatic model routing (open source has opt-in, rule-based routing), prompt-injection and risky-tool-call removal, SSO, managed or VPC deployment, an org-wide savings dashboard, and support. Companies that sign a 12-month Enterprise plan get the first 3 months free.\n\n- [Headroom for Teams](https://docs.headroomlabs.ai/docs/teams): Open source vs Enterprise, and the 3-months-free offer.\n- [Claim 3 months free](https://headroom-perks.vercel.app/?source=github&utm_source=llms-txt): Perk sign-up form. One perk per company.\n\n## Licensing\n\nApache 2.0. Use commercially, modify, redistribute. Data stays on the user's machine when running the library, proxy, or MCP server locally. An anonymous usage beacon is **on by default**: it reports compression ratios, counters, provider and model IDs, OS and architecture, and never prompts, completions, code or file paths. Turn it off with `HEADROOM_BEACON=off`, `DO_NOT_TRACK=1`, or `HEADROOM_OFFLINE=1`. See [Telemetry](https://github.com/headroomlabs-ai/headroom#telemetry).\n","isInternal":false,"tokens":1642,"sizeBytes":6406},{"name":"api.md","path":"wiki/api.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/wiki/api.md","title":"wiki - API Interface Contract & Specifications","category":"project-spec","format":"markdown","content":"# API Reference\n\n## HeadroomClient\n\nThe main entry point for Headroom SDK.\n\n```python\nfrom headroom import HeadroomClient\nfrom openai import OpenAI\n\nclient = HeadroomClient(\n    original_client=OpenAI(),\n    default_mode=\"optimize\",\n)\n```\n\n### Constructor Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `original_client` | `OpenAI \\| Anthropic` | Required | The underlying LLM client |\n| `provider` | `Provider` | Required (no default) | Token counting provider — e.g. `OpenAIProvider()`, `AnthropicProvider()` |\n| `default_mode` | `str` | `\"audit\"` | Default mode: \"audit\", \"optimize\", \"off\" |\n| `store_url` | `str` | `None` | Storage URL for metrics |\n| `model_context_limits` | `dict[str, int]` | `None` | Override context limits for models |\n| `cache_optimizer` | `BaseCacheOptimizer` | `None` (auto-detect) | Custom cache optimizer |\n| `enable_cache_optimizer` | `bool` | `True` | Enable provider-specific cache optimization |\n| `enable_semantic_cache` | `bool` | `False` | Enable query-level semantic caching |\n| `config` | `HeadroomConfig` | `None` | Full config object; set `config.smart_crusher` / `config.cache_aligner` here to override compression/cache-alignment settings — there is no separate `smart_crusher_config`/`cache_aligner_config` constructor kwarg |\n\n### Methods\n\n#### `chat.completions.create(**kwargs)`\n\nCreate a chat completion with optional optimization.\n\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[...],\n    headroom_mode=\"optimize\",  # Override default mode\n)\n```\n\n**Additional Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `headroom_mode` | `str` | Override mode for this request |\n| `headroom_query` | `str` | Query for relevance scoring |\n\n#### `chat.completions.simulate(**kwargs)`\n\nPreview optimization without making an API call.\n\n```python\nplan = client.chat.completions.simulate(\n    model=\"gpt-4o\",\n    messages=[...],\n)\n\nprint(f\"Tokens before: {plan.tokens_before}\")\nprint(f\"Tokens after: {plan.tokens_after}\")\nprint(f\"Savings: {plan.savings_percent:.1f}%\")\n```\n\n**Returns:** `SimulationResult`\n\n---\n\n## Configuration Classes\n\n### SmartCrusherConfig\n\n```python\nfrom headroom import SmartCrusherConfig\n\nconfig = SmartCrusherConfig(\n    min_tokens_to_crush=200,\n    max_items_after_crush=50,\n    keep_first=3,\n    keep_last=2,\n    relevance_threshold=0.3,\n    anomaly_std_threshold=2.0,\n    preserve_errors=True,\n)\n```\n\n### CacheAlignerConfig\n\n```python\nfrom headroom import CacheAlignerConfig\n\nconfig = CacheAlignerConfig(\n    extract_dates=True,\n    normalize_whitespace=True,\n    stable_prefix_min_tokens=100,\n)\n```\n\n### RelevanceScorerConfig\n\n```python\nfrom headroom import RelevanceScorerConfig\n\nconfig = RelevanceScorerConfig(\n    scorer_type=\"bm25\",  # \"bm25\", \"embedding\", or \"hybrid\"\n    embedding_model=None,  # Model name for embedding scorer\n    hybrid_alpha=0.5,  # Weight for hybrid scoring\n)\n```\n\n---\n\n## Data Models\n\n### SimulationResult\n\nReturned by `simulate()`.\n\n```python\n@dataclass\nclass SimulationResult:\n    tokens_before: int\n    tokens_after: int\n    tokens_saved: int\n    savings_percent: float\n    transforms_applied: list[str]\n    waste_signals: WasteSignals\n```\n\n### RequestMetrics\n\nMetrics for a single request.\n\n```python\n@dataclass\nclass RequestMetrics:\n    request_id: str\n    timestamp: datetime\n    model: str\n    tokens_input_before: int\n    tokens_input_after: int\n    tokens_output: int\n    cost_before: float\n    cost_after: float\n    transforms_applied: list[str]\n```\n\n### WasteSignals\n\nDetected waste in the request.\n\n```python\n@dataclass\nclass WasteSignals:\n    json_bloat_tokens: int\n    html_noise_tokens: int\n    whitespace_tokens: int\n    dynamic_date_tokens: int\n    repetition_tokens: int\n```\n\n---\n\n## Providers\n\n### OpenAIProvider\n\n```python\nfrom headroom import OpenAIProvider\n\nprovider = OpenAIProvider()\n\n# Get token counter\ncounter = provider.get_token_counter(\"gpt-4o\")\ntokens = counter.count_text(\"Hello, world!\")\n\n# Get context limit\nlimit = provider.get_context_limit(\"gpt-4o\")  # 128000\n\n# Estimate cost\ncost = provider.estimate_cost(\n    input_tokens=1000,\n    output_tokens=500,\n    model=\"gpt-4o\",\n)\n```\n\n### AnthropicProvider\n\n```python\nfrom headroom import AnthropicProvider\nfrom anthropic import Anthropic\n\nprovider = AnthropicProvider(client=Anthropic())\n\ncounter = provider.get_token_counter(\"claude-3-5-sonnet-latest\")\ntokens = counter.count_messages(messages)  # Accurate count via API\n```\n\n---\n\n## Relevance Scoring\n\n### BM25Scorer\n\nFast keyword-based scoring (zero dependencies).\n\n```python\nfrom headroom import BM25Scorer\n\nscorer = BM25Scorer()\nscores = scorer.score_items(\n    items=[\"item 1\", \"item 2\", ...],\n    query=\"search query\",\n)\n```\n\n### EmbeddingScorer\n\nSemantic similarity scoring (requires `sentence-transformers`).\n\n```python\nfrom headroom import EmbeddingScorer, embedding_available\n\nif embedding_available():\n    scorer = EmbeddingScorer(model=\"all-MiniLM-L6-v2\")\n    scores = scorer.score_items(items, query)\n```\n\n### HybridScorer\n\nCombines BM25 and embeddings.\n\n```python\nfrom headroom import HybridScorer\n\nscorer = HybridScorer(alpha=0.5)  # 50% BM25, 50% embedding\nscores = scorer.score_items(items, query)\n```\n\n### create_scorer()\n\nFactory function to create scorers.\n\n```python\nfrom headroom import create_scorer\n\n# Auto-select best available scorer\nscorer = create_scorer()\n\n# Explicitly choose type\nscorer = create_scorer(scorer_type=\"hybrid\", alpha=0.7)\n```\n\n---\n\n## Transforms (Direct Use)\n\n### SmartCrusher\n\n```python\nfrom headroom import SmartCrusher\n\ncrusher = SmartCrusher()\nresult = crusher.crush(\n    data={\"results\": [...]},\n    query=\"user query\",\n)\n```\n\n### CacheAligner\n\n```python\nfrom headroom import CacheAligner\n\naligner = CacheAligner()\nresult = aligner.align(messages)\n```\n\n> **Context management** is handled automatically inside the pipeline\n> (live-zone-only compression). The position-based `RollingWindow` and\n> score-based `IntelligentContextManager` / `MessageScorer` APIs have been\n> removed and are no longer part of Headroom.\n\n### TransformPipeline\n\n```python\nfrom headroom import TransformPipeline\n\npipeline = TransformPipeline(\n    [\n        SmartCrusher(),\n        CacheAligner(),\n    ]\n)\n\nresult = pipeline.transform(messages)\n```\n\n---\n\n## Utilities\n\n### Tokenizer\n\n```python\nfrom headroom import Tokenizer, count_tokens_text, count_tokens_messages\n\n# Quick counting\ntokens = count_tokens_text(\"Hello, world!\", model=\"gpt-4o\")\n\n# With tokenizer instance\ntokenizer = Tokenizer(model=\"gpt-4o\")\ntokens = tokenizer.count_text(\"Hello\")\ntokens = tokenizer.count_messages(messages)\n```\n\n### generate_report()\n\nGenerate HTML/Markdown reports from stored metrics.\n\n```python\nfrom headroom import generate_report\n\nreport = generate_report(\n    store_url=\"sqlite:///headroom.db\",\n    format=\"html\",\n    period=\"day\",\n)\n```\n\n---\n\n## TypeScript SDK\n\nFor the TypeScript SDK API reference, see [TypeScript SDK](typescript-sdk.md).\n\nThe TypeScript SDK provides `compress()`, `HeadroomClient`, and framework adapters for Vercel AI SDK, OpenAI, and Anthropic.\n","isInternal":false,"tokens":1781,"sizeBytes":7151},{"name":"ARCHITECTURE.md","path":"wiki/ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/wiki/ARCHITECTURE.md","title":"wiki - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# Headroom SDK: A Complete Explanation\n\n## Architecture Overview\n\n```mermaid\nflowchart TB\n    subgraph Entry[\"Entry Points\"]\n        Proxy[\"Proxy Mode<br/><i>Zero code changes</i>\"]\n        SDK[\"SDK Mode<br/><i>HeadroomClient</i>\"]\n        Integrations[\"Integrations<br/><i>LangChain / Agno</i>\"]\n    end\n\n    subgraph Pipeline[\"Transform Pipeline\"]\n        direction TB\n\n        CA[\"Cache Aligner<br/>━━━━━━━━━━━━━━━<br/>Extracts dynamic content<br/>(dates, UUIDs, tokens)<br/>Stable prefix for caching\"]\n\n        SC[\"Smart Crusher<br/>━━━━━━━━━━━━━━━<br/>Analyzes tool outputs<br/>Keeps: first, last, errors, outliers<br/>70-95% reduction\"]\n\n        CM[\"Context Manager<br/>━━━━━━━━━━━━━━━<br/>Enforces token limits<br/>Scores by recency and relevance<br/>Fits context window\"]\n\n        CA --> SC --> CM\n    end\n\n    subgraph Cache[\"Provider Cache Optimization\"]\n        direction LR\n        Anthropic[\"Anthropic<br/><i>cache_control blocks</i><br/>90% savings\"]\n        OpenAI[\"OpenAI<br/><i>Prefix alignment</i><br/>50% savings\"]\n        Google[\"Google<br/><i>CachedContent API</i><br/>75% savings\"]\n    end\n\n    subgraph CCR[\"CCR: Compress-Cache-Retrieve\"]\n        Store[(\"Compression<br/>Store\")]\n        Tool[\"Retrieve Tool<br/><i>LLM requests original</i>\"]\n        Store <--> Tool\n    end\n\n    LLM[\"LLM API<br/><i>OpenAI / Anthropic / Google</i>\"]\n\n    Entry --> Pipeline\n    Pipeline --> Cache\n    Cache --> LLM\n    SC -.->|\"Stores original\"| Store\n    LLM -.->|\"If needed\"| Tool\n```\n\n---\n\n## What Problem Does Headroom Solve?\n\nWhen you use AI models like GPT-4 or Claude, you pay for **tokens** - the pieces of text you send (input) and receive (output). The problem is:\n\n1. **Tool outputs are HUGE**: When an AI agent calls tools (search, database queries, APIs), the responses are often massive JSON blobs with thousands of tokens\n2. **Most of that data is REDUNDANT**: 60 metric data points showing `cpu: 45%` repeated, or 50 log entries with the same error message\n3. **You're paying for waste**: Every token costs money and adds latency\n4. **Context windows fill up**: Models have limits (128K tokens), and bloated tool outputs eat into your available space\n\n**Headroom creates \"headroom\"** - it intelligently compresses your input tokens so you have more room (and budget) for what matters.\n\n---\n\n## How Headroom Works: The Big Picture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        YOUR APPLICATION                          │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      HEADROOM CLIENT                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │\n│  │   ANALYZE   │→ │  TRANSFORM  │→ │    CALL     │             │\n│  │  (Parser)   │  │  (Pipeline) │  │   (API)     │             │\n│  └─────────────┘  └─────────────┘  └─────────────┘             │\n│         │                │                │                     │\n│         ▼                ▼                ▼                     │\n│   Count tokens     Apply compressions   Send to OpenAI/Claude  │\n│   Detect waste     Preserve meaning     Log metrics            │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                    OPENAI / ANTHROPIC API                        │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Core Components (In Simple Terms)\n\n### 1. HeadroomClient (`client.py`) - The Wrapper\n\n`HeadroomClient` is still exported (`headroom/__init__.py:93,197`), but it is\nno longer the only SDK entry point: the site's current architecture\ndocumentation (`docs/content/docs/architecture.mdx`) describes SDK mode as\ncalling the one-function `compress()` API (`headroom.compress`,\n`headroom.CompressConfig`) directly on your messages, with `HeadroomClient`\nas the client-wrapping alternative. Both exist; this section covers only the\nwrapper.\n\nThis is what you interact with. It wraps your existing OpenAI or Anthropic client:\n\n```python\n# Before (normal OpenAI)\nclient = OpenAI(api_key=\"...\")\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n\n# After (with Headroom)\nbase = OpenAI(api_key=\"...\")\nclient = HeadroomClient(original_client=base, provider=OpenAIProvider())\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n```\n\n**What it does:**\n- Intercepts your API calls\n- Runs messages through the transform pipeline\n- Calls the real API with optimized messages\n- Logs metrics to a database\n- Returns the response unchanged\n\n**Two modes:**\n- `audit`: Just observe and log (no changes)\n- `optimize`: Apply transforms to reduce tokens\n\n---\n\n### 2. Providers (`providers/`) - Model-Specific Knowledge\n\nDifferent AI providers have different rules:\n\n```python\nclass OpenAIProvider:\n    # Knows GPT-4o has 128K context\n    # Knows how to count tokens (tiktoken)\n    # Knows pricing ($2.50 per million input tokens)\n\nclass AnthropicProvider:\n    # Knows Claude has 200K context\n    # Uses different tokenization (~4 chars per token)\n    # Different pricing structure\n```\n\n**Why this matters:** Token counting is model-specific. GPT-4 uses different tokenization than Claude. Headroom needs accurate counts to know how much to compress.\n\n---\n\n### 3. Parser (`parser.py`) - Understanding Your Messages\n\nBefore optimizing, Headroom needs to understand what's in your messages:\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are helpful...\"},\n    {\"role\": \"user\", \"content\": \"Search for X\"},\n    {\"role\": \"assistant\", \"tool_calls\": [...]},\n    {\"role\": \"tool\", \"content\": \"{huge JSON}\"},\n]\n\n# Parser breaks this into \"blocks\":\nblocks = [\n    Block(kind=\"system\", tokens=50, ...),\n    Block(kind=\"user\", tokens=10, ...),\n    Block(kind=\"tool_call\", tokens=20, ...),\n    Block(kind=\"tool_result\", tokens=5000, ...),  # ← This is the problem!\n]\n```\n\n**It also detects waste signals:**\n- Large JSON blobs (>500 tokens)\n- HTML tags and comments\n- Base64 encoded data\n- Excessive whitespace\n\n---\n\n### 4. Transforms (`transforms/`) - The Compression Magic\n\nThis is where the real work happens. Headroom has 4 transforms that run in sequence:\n\n#### Transform 1: Cache Aligner\n\n**Problem:** LLM providers cache your prompts, but only if they're byte-identical. If your system prompt has today's date, every day is a cache miss.\n\n```python\n# Before:\n\"You are helpful. Current Date: 2024-12-15\"  # Changes daily = no cache\n\n# After:\n\"You are helpful.\"  # Static = cacheable\n\"[Context: Current Date: 2024-12-15]\"  # Dynamic part moved to end\n```\n\n**How it works:**\n1. Find date patterns in system prompt\n2. Extract them\n3. Move to end of message\n4. Now the PREFIX is stable → cache hits!\n\n---\n\n#### Transform 2: Tool Crusher (Naive) - DISABLED BY DEFAULT\n\nThis was our first approach - simple but limited:\n\n```python\n# Before: 60 items\n[{\"ts\": 1, \"cpu\": 45}, {\"ts\": 2, \"cpu\": 45}, ..., {\"ts\": 60, \"cpu\": 95}]\n\n# After: First 10 items only\n[{\"ts\": 1, \"cpu\": 45}, ..., {\"ts\": 10, \"cpu\": 45}, {\"__truncated\": 50}]\n```\n\n**Problem:** If the important data (CPU spike) is at position 45, it gets thrown away!\n\n---\n\n#### Transform 3: Smart Crusher (NEW DEFAULT)\n\nThis is the intelligent approach using **statistical analysis**:\n\n```python\n# Analyzes the data first:\nanalysis = {\n    \"ts\": {\"type\": \"sequential\", \"unique_ratio\": 1.0},\n    \"host\": {\"type\": \"constant\", \"value\": \"prod-1\"},  # ← Same everywhere!\n    \"cpu\": {\"variance\": 892, \"change_points\": [45]},  # ← Spike detected!\n}\n\n# Smart compression:\n{\n    \"__headroom_constants\": {\"host\": \"prod-1\"},  # Factor out\n    \"__headroom_summary\": \"items 0-44: cpu stable at ~45\",  # Summarize boring part\n    \"data\": [\n        {\"ts\": 45, \"cpu\": 92},  # Keep the spike!\n        {\"ts\": 46, \"cpu\": 95},\n        ...,\n    ],\n}\n```\n\n**Strategies it uses:**\n1. **TIME_SERIES**: Detect variance spikes, keep change points\n2. **CLUSTER**: Group similar log messages, keep 1-2 per cluster\n3. **TOP_N**: For search results, keep highest scored\n4. **SMART_SAMPLE**: Statistical sampling with constant extraction\n\n---\n\n#### Transform 4: ML Compressor (Optional, Kompress)\n\n**When to use:** Maximum compression needed and latency is acceptable.\n\nThe proxy ships an opt-in ML compression path backed by **Kompress**\n(ModernBERT-based token classifier). Install with `pip install\n'headroom-ai[ml]'`; see `wiki/transforms.md` for current configuration.\n\n**Note:** The earlier LLMLingua-2 integration (`--llmlingua` flag, the\n`headroom-ai[llmlingua]` extra, and the `LLMLinguaCompressor` class) was\nretired and replaced by Kompress. `pip install 'headroom-ai[llmlingua]'`\nno longer resolves; use `[ml]` instead.\n\n---\n\n#### Context Management: Live-Zone-Only Compression\n\n**Approach:** Headroom never drops messages from conversation history, and it does not do position-based or score-based context management. Context management is handled automatically inside the pipeline by compressing only the **live zone** — the newest content blocks (the latest user message and the latest tool result / tool output).\n\n```\n# The cache hot zone is NEVER mutated:\n# - System prompt\n# - Tool definitions\n# - Older conversation turns\n#\n# Only the newest content blocks are compressed (type-aware),\n# and every compression is reversible via CCR.\n```\n\n**Why this matters:** Leaving the hot zone untouched preserves provider prompt caching (e.g. Claude's cached-prefix read discount). Because only the newest blocks change, earlier turns stay byte-stable across requests and keep hitting the KV cache. Compression is type-aware (handled by ContentRouter and its compressors) and fully reversible — the LLM can call `headroom_retrieve` to restore any compressed block.\n\n---\n\n### 5. Storage (`storage/`) - Metrics Database\n\nEvery request is logged:\n\n```sql\nCREATE TABLE requests (\n    id TEXT PRIMARY KEY,\n    timestamp TEXT,\n    model TEXT,\n    mode TEXT,  -- audit or optimize\n    tokens_input_before INTEGER,  -- Before Headroom\n    tokens_input_after INTEGER,   -- After Headroom\n    tokens_saved INTEGER,         -- The win!\n    transforms_applied TEXT,      -- What we did\n    ...\n);\n```\n\nThis lets you:\n- See how much you're saving\n- Generate reports\n- Track trends over time\n\n---\n\n## The Data Flow (Step by Step)\n\nLet's trace a real request:\n\n### Step 1: You call the API\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are an SRE. Date: 2024-12-15\"},\n        {\"role\": \"user\", \"content\": \"Check the metrics\"},\n        {\"role\": \"assistant\", \"tool_calls\": [...]},\n        {\"role\": \"tool\", \"content\": \"{60 metric points...}\"},  # 5000 tokens!\n        {\"role\": \"user\", \"content\": \"What's wrong?\"},\n    ],\n    headroom_mode=\"optimize\",\n)\n```\n\n### Step 2: HeadroomClient intercepts\n```python\n# In client.py:\ndef _create(self, messages, ...):\n    # 1. Parse messages into blocks\n    blocks, breakdown, waste = parse_messages(messages, tokenizer)\n    # breakdown = {\"system\": 50, \"user\": 20, \"tool_result\": 5000, ...}\n\n    # 2. Count original tokens\n    tokens_before = 5100\n```\n\n### Step 3: Transform Pipeline runs\n```python\n# In pipeline.py:\ndef apply(self, messages, ...):\n    # Transform 1: Cache Aligner\n    # - Extracts \"Date: 2024-12-15\" from system prompt\n    # - Moves to end\n\n    # Transform 2: Smart Crusher\n    # - Analyzes 60 metric points\n    # - Detects CPU spike at point 45\n    # - Compresses to 17 points (preserving spike)\n    # - Factors out constant \"host\" field\n\n    # Transform 3: Kompress ML compressor (opt-in via headroom-ai[ml])\n    # - ModernBERT-based compression on remaining long text\n    # - Auto-detects content type for optimal rate\n    # - Stores original in CCR for retrieval\n\n    # Transform 4: Rolling Window\n    # - Checks if we're under limit (we are)\n    # - No drops needed\n\n    return TransformResult(\n        messages=optimized,\n        tokens_before=5100,\n        tokens_after=1200,  # 76% reduction!\n        transforms=[\"cache_align\", \"smart_crush:1\"]\n    )\n```\n\n### Step 4: Call real API\n```python\n# In client.py:\nresponse = self._original.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=optimized_messages,  # Only 1200 tokens now!\n)\n```\n\n### Step 5: Log metrics and return\n```python\n# Save to database\nmetrics = RequestMetrics(\n    tokens_input_before=5100,\n    tokens_input_after=1200,\n    tokens_saved=3900,  # 76%!\n    ...\n)\nstorage.save(metrics)\n\nreturn response  # Unchanged from API\n```\n\n---\n\n## The Smart Crusher Deep Dive\n\nThis is the most sophisticated part. Here's how it analyzes data:\n\n### Field Analysis\n```python\ndef analyze_field(key, items):\n    values = [item[key] for item in items]\n\n    return {\n        \"unique_ratio\": len(set(values)) / len(values),\n        # 0.0 = all same (constant)\n        # 1.0 = all different (unique IDs)\n        \"variance\": statistics.variance(values),  # For numbers\n        # Low = stable\n        # High = changing\n        \"change_points\": detect_spikes(values),\n        # Indices where value jumps significantly\n    }\n```\n\n### Pattern Detection\n```python\ndef detect_pattern(field_stats):\n    # Has timestamp + numeric variance? → TIME_SERIES\n    if has_timestamp and has_numeric_variance:\n        return \"time_series\"\n\n    # Has message field + level field? → LOGS\n    if has_message_field and has_level_field:\n        return \"logs\"\n\n    # Has score/rank field? → SEARCH_RESULTS\n    if has_score_field:\n        return \"search_results\"\n\n    return \"generic\"\n```\n\n### Compression Strategy\n```python\ndef compress(items, analysis):\n    if analysis.pattern == \"time_series\":\n        # Keep points around change points\n        # Summarize stable regions\n        return time_series_compress(items, analysis.change_points)\n\n    elif analysis.pattern == \"logs\":\n        # Cluster similar messages\n        # Keep 1-2 per cluster\n        return cluster_compress(items, analysis.clusters)\n\n    elif analysis.pattern == \"search_results\":\n        # Sort by score\n        # Keep top N\n        return top_n_compress(items, analysis.score_field)\n```\n\n---\n\n## CCR Architecture: Compress-Cache-Retrieve\n\n### The Key Insight\n\n> \"Prefer raw > Compaction > Summarization only when compaction no longer yields enough space. Compaction (Reversible) strips out information that is redundant because it exists in the environment—if the agent needs to read the data later, it can use a tool to retrieve it.\" — Phil Schmid, Context Engineering\n\n**The problem with traditional compression:** If we guess wrong about what's important, we've permanently lost data. The LLM might need something we threw away.\n\n**CCR's solution:** Make compression **reversible**. When SmartCrusher compresses, the original data is cached. If the LLM needs more, it can retrieve instantly.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  TOOL OUTPUT (1000 items)                                         │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  HEADROOM CCR LAYER                                               │\n│                                                                   │\n│  1. COMPRESS: Keep 20 items (errors, anomalies, relevant)        │\n│  2. CACHE: Store full 1000 items in fast local cache             │\n│  3. INJECT: Add retrieval capability to LLM context              │\n│                                                                   │\n│  \"20 items shown. Use /v1/retrieve?hash=xxx for more.\"           │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  LLM PROCESSING                                                   │\n│                                                                   │\n│  Option A: LLM solves task with 20 items → Done                  │\n│  Option B: LLM needs more → retrieves via API                    │\n│            → We fetch from cache → Return instantly              │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  FEEDBACK LOOP                                                    │\n│                                                                   │\n│  Track: What did the LLM retrieve? What queries?                 │\n│  Learn: \"For this tool, keep items matching common queries\"      │\n│  Improve: Next compression uses learned patterns                 │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### CCR Phase 1: Compression Store\n\n**Location:** `headroom/cache/compression_store.py`\n\nWhen SmartCrusher compresses, the original content is stored for on-demand retrieval:\n\n```python\n@dataclass\nclass CompressionEntry:\n    hash: str  # 24-char SHA256 prefix for retrieval\n    original_content: str  # Full JSON before compression\n    compressed_content: str  # Compressed JSON\n    original_item_count: int\n    compressed_item_count: int\n    tool_name: str | None  # For feedback tracking\n    created_at: float\n    ttl: int = 1800  # 30 minute default (DEFAULT_CCR_TTL_SECONDS)\n```\n\n**Features:**\n- Thread-safe in-memory storage\n- TTL-based expiration (default 30 minutes; `DEFAULT_CCR_TTL_SECONDS`, override via `HEADROOM_CCR_TTL_SECONDS`)\n- LRU-style eviction when capacity reached\n- Hash-keyed retrieval that always returns the full original content\n\n**Usage:**\n```python\nstore = get_compression_store()\n\n# Store compressed content\nhash_key = store.store(\n    original=original_json,\n    compressed=compressed_json,\n    original_item_count=1000,\n    compressed_item_count=20,\n    tool_name=\"search_api\",\n)\n\n# Retrieve later (by hash; always returns the full original content)\nentry = store.retrieve(hash_key)\n```\n\n---\n\n### CCR Phase 2: Retrieval API\n\n**Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/retrieve` | POST | Retrieve original content by hash |\n| `/v1/retrieve/{hash}` | GET | Retrieve original content by hash |\n\nRetrieval is by hash only — it always returns the full original content.\n\n**Retrieval Request:**\n```json\n{\n    \"hash\": \"abc123def456...\"\n}\n```\n\n**Response:**\n```json\n{\n    \"hash\": \"abc123def456...\",\n    \"original_content\": \"[{...}, {...}, ...]\",\n    \"original_item_count\": 1000,\n    \"tool_name\": \"search_api\"\n}\n```\n\n---\n\n### CCR Phase 3: Tool Injection\n\nWhen compression happens, Headroom injects retrieval instructions into the LLM context.\n\n**Method A: System Message Injection**\n```\n## Compressed Context Available\nThe following tool outputs have been compressed. If you need more detail,\ncall the retrieve_compressed tool with the hash.\n\nAvailable: hash=abc123 (1000→20 items from search_api)\n```\n\n**Method B: MCP Tool Registration (Hybrid)**\nWhen running as MCP server, Headroom exposes retrieval as a tool:\n\n```json\n{\n    \"name\": \"headroom_retrieve\",\n    \"description\": \"Retrieve more items from compressed tool output\",\n    \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"hash\": {\"type\": \"string\"}\n        },\n        \"required\": [\"hash\"]\n    }\n}\n```\n\n**Marker Injection:**\nCompressed content includes retrieval markers:\n```json\n{\n    \"__headroom_compressed\": true,\n    \"__headroom_hash\": \"abc123def456\",\n    \"__headroom_stats\": {\n        \"original_items\": 1000,\n        \"kept_items\": 20,\n        \"errors_preserved\": 5\n    },\n    \"data\": [...]\n}\n```\n\n---\n\n### CCR Phase 4: Feedback Loop\n\n**Location:** `headroom/cache/compression_feedback.py`\n\nThe feedback system learns from retrieval patterns to improve future compression.\n\n**Tracked Patterns per Tool:**\n```python\n@dataclass\nclass ToolPattern:\n    tool_name: str\n    total_compressions: int  # Times we compressed this tool\n    total_retrievals: int  # Times LLM asked for more\n    full_retrievals: int  # Retrieved everything (all retrievals — hash-only)\n    search_retrievals: int  # Legacy; always 0 (retrieval is hash-only, no search)\n    common_queries: dict[str, int]  # Legacy query-pattern frequency (no longer populated)\n    queried_fields: dict[str, int]  # Legacy queried-field frequency (no longer populated)\n```\n\n**Key Metrics:**\n- **Retrieval Rate**: `total_retrievals / total_compressions`\n  - High (>50%) → Compressing too aggressively\n  - Low (<20%) → Compression is effective\n- **Full Retrieval Rate**: `full_retrievals / total_retrievals`\n  - High (>80%) → Data is unique, consider skipping compression\n\n**Compression Hints:**\n```python\n@dataclass\nclass CompressionHints:\n    max_items: int = 15  # Target item count\n    suggested_items: int | None  # Calculated optimal\n    skip_compression: bool  # Don't compress at all\n    preserve_fields: list[str]  # Always keep these fields\n    aggressiveness: float  # 0.0 = aggressive, 1.0 = conservative\n    reason: str  # Explanation\n```\n\n**Feedback-Driven Adjustment:**\n```python\n# In SmartCrusher._crush_array()\nif self.config.use_feedback_hints and tool_name:\n    feedback = get_compression_feedback()\n    hints = feedback.get_compression_hints(tool_name)\n\n    if hints.skip_compression:\n        return items, f\"skip:feedback({hints.reason})\", None\n\n    if hints.suggested_items is not None:\n        self.config.max_items_after_crush = hints.suggested_items\n```\n\n**Feedback Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/feedback` | GET | Get all learned patterns |\n| `/v1/feedback/{tool_name}` | GET | Get hints for specific tool |\n\n**Example Response:**\n```json\n{\n    \"total_compressions\": 150,\n    \"total_retrievals\": 23,\n    \"global_retrieval_rate\": 0.15,\n    \"tools_tracked\": 5,\n    \"tool_patterns\": {\n        \"search_api\": {\n            \"compressions\": 50,\n            \"retrievals\": 5,\n            \"retrieval_rate\": 0.10,\n            \"full_rate\": 0.20,\n            \"search_rate\": 0.80,\n            \"common_queries\": [\"status:error\", \"level:critical\"],\n            \"queried_fields\": [\"status\", \"level\", \"message\"]\n        }\n    }\n}\n```\n\n---\n\n### CCR Phase 5: Response Handler (Automatic Tool Call Handling)\n\n**Location:** `headroom/ccr/response_handler.py`\n\n**The Problem:** When the proxy injects the `headroom_retrieve` tool, the LLM might call it. But who handles that tool call? Without response handling, the tool call would go back to the client unhandled.\n\n**The Solution:** The Response Handler intercepts LLM responses, detects CCR tool calls, executes retrievals automatically, and continues the conversation until the LLM produces a final response.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  RESPONSE HANDLER FLOW                                           │\n│                                                                   │\n│  1. LLM Response arrives                                         │\n│     └─ Contains: tool_use(headroom_retrieve, hash=abc123)       │\n│                                                                   │\n│  2. Handler detects CCR tool call                                │\n│     └─ Extracts hash                                             │\n│                                                                   │\n│  3. Handler executes retrieval                                   │\n│     └─ By hash: store.retrieve(hash) → full original content    │\n│                                                                   │\n│  4. Handler continues conversation                               │\n│     └─ Adds tool result to messages                             │\n│     └─ Makes another API call                                   │\n│                                                                   │\n│  5. Repeat until no CCR tool calls                              │\n│     └─ Max 3 rounds (configurable)                              │\n│                                                                   │\n│  6. Return final response to client                             │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CCRToolCall:\n    tool_call_id: str  # For matching response\n    hash_key: str  # CCR hash to retrieve\n\n\n@dataclass\nclass CCRToolResult:\n    tool_call_id: str\n    content: str  # Retrieved data as JSON\n    success: bool\n    items_retrieved: int\n\n\nclass CCRResponseHandler:\n    async def handle_response(\n        self,\n        response: dict,  # Initial LLM response\n        messages: list,  # Conversation history\n        tools: list,  # Tool definitions\n        api_call_fn: Callable,  # Function to make API calls\n        provider: str,  # \"anthropic\" or \"openai\"\n    ) -> dict:\n        \"\"\"Handle CCR tool calls until final response.\"\"\"\n```\n\n**Streaming Support:**\n\nThe handler also supports streaming responses via `StreamingCCRHandler`:\n\n```python\nclass StreamingCCRBuffer:\n    \"\"\"Buffers streaming chunks to detect CCR tool calls.\"\"\"\n\n    chunks: list[bytes]\n    detected_ccr: bool\n\n\nclass StreamingCCRHandler:\n    \"\"\"Handles CCR in streaming responses.\"\"\"\n\n    async def process_stream(self, stream, messages, tools, api_call_fn):\n        \"\"\"Yields chunks, switching to buffered mode if CCR detected.\"\"\"\n```\n\n---\n\n### CCR Phase 6: Context Tracker (Multi-Turn Awareness)\n\n**Location:** `headroom/ccr/context_tracker.py`\n\n**The Problem:** In multi-turn conversations, earlier compressed data might become relevant later. Without tracking, the LLM has \"context amnesia\" - it can't reference data that was compressed in turn 1 when answering a question in turn 5.\n\n**The Solution:** The Context Tracker maintains awareness of all compressed content across the conversation and can proactively expand relevant data when a new query might need it.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  CONTEXT TRACKER FLOW                                            │\n│                                                                   │\n│  Turn 1: Search returns 100 files → compressed to 10            │\n│          Tracker stores: hash=abc123, sample=\"auth.py, db.py\"   │\n│                                                                   │\n│  Turn 5: User asks \"What about the authentication middleware?\"  │\n│          Tracker analyzes query:                                 │\n│          - \"authentication\" matches \"auth.py\" in sample         │\n│          - Relevance score: 0.7 (above threshold)               │\n│                                                                   │\n│  Proactive Expansion:                                           │\n│          - Retrieves abc123 before LLM responds                 │\n│          - Adds expanded context to request                     │\n│                                                                   │\n│  Result: LLM sees full file list, can answer accurately         │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CompressedContext:\n    hash_key: str              # CCR hash\n    turn_number: int           # When compression happened\n    timestamp: float           # For age-based filtering\n    tool_name: str | None      # Which tool was compressed\n    original_item_count: int\n    compressed_item_count: int\n    query_context: str         # User query at compression time\n    sample_content: str        # Preview for relevance matching\n\n@dataclass\nclass ExpansionRecommendation:\n    hash_key: str\n    reason: str                # Human-readable explanation\n    relevance_score: float     # 0-1, higher = more relevant\n    # Expansion always restores the full original content (retrieval is by hash).\n\nclass ContextTracker:\n    def track_compression(self, hash_key, turn_number, ...):\n        \"\"\"Track a compression event.\"\"\"\n\n    def analyze_query(self, query: str) -> list[ExpansionRecommendation]:\n        \"\"\"Find relevant compressed contexts for a query.\"\"\"\n\n    def execute_expansions(self, recommendations) -> list[dict]:\n        \"\"\"Execute recommended expansions.\"\"\"\n```\n\n**Relevance Calculation:**\n\nThe tracker uses simple but effective heuristics:\n\n1. **Keyword overlap with sample content** - Extract keywords from query, match against compressed content preview\n2. **Keyword overlap with original query** - Match against the query that triggered compression\n3. **Tool name relevance** - File operations more likely to need expansion for \"file\", \"where\", \"find\" queries\n4. **Age discount** - Older contexts get lower scores\n\n**Configuration:**\n\n```python\n@dataclass\nclass ContextTrackerConfig:\n    enabled: bool = True\n    max_tracked_contexts: int = 100  # LRU eviction\n    relevance_threshold: float = 0.3  # Min score to recommend\n    max_context_age_seconds: float = 300  # 5 minutes\n    proactive_expansion: bool = True\n    max_proactive_expansions: int = 2  # Per query\n```\n\n---\n\n### Why CCR is a Moat\n\n1. **Reversible**: No permanent information loss. Worst case = retrieve everything.\n2. **Transparent**: LLM knows it can ask for more data.\n3. **Automatic**: Response Handler executes retrievals without client intervention.\n4. **Context-Aware**: Context Tracker prevents multi-turn amnesia.\n5. **Feedback Loop**: Learn from actual needs, not guesses.\n6. **Network Effect**: Retrieval patterns across users improve compression for everyone.\n7. **Zero-Risk**: If compression fails, instant fallback to original data.\n\n---\n\n## Image Compression Architecture\n\nVision models charge by the token, and images are expensive (765-2900 tokens for a typical image). Headroom's image compression uses a **trained ML router** to automatically select the optimal compression technique.\n\n### The Key Insight\n\nNot all image queries need full resolution:\n- \"What is this?\" → Low detail is fine (87% savings)\n- \"Count the whiskers\" → Need full detail (0% savings)\n- \"Read the sign\" → Could convert to text (99% savings)\n\n### How It Works\n\n```\nUser: [image] + \"What animal is this?\"\n           ↓\n┌─────────────────────────────────┐\n│  1. Query Analysis              │\n│  TrainedRouter (MiniLM)         │\n│  Classifies → full_low          │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  2. Image Analysis (Optional)   │\n│  SigLIP checks:                 │\n│  - Has text? Is complex?        │\n│  - Fine details needed?         │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  3. Apply Compression           │\n│  OpenAI: detail=\"low\"           │\n│  Anthropic: Resize to 512px     │\n│  Google: Resize to 768px        │\n└─────────────────────────────────┘\n           ↓\nCompressed request → LLM → Response\n```\n\n### The Trained Router\n\nA fine-tuned MiniLM classifier hosted on HuggingFace:\n\n- **Model**: `chopratejas/technique-router`\n- **Size**: ~128MB (downloaded once, cached)\n- **Accuracy**: 93.7% on 1,157 training examples\n- **Latency**: ~10ms CPU, ~2ms GPU\n\nThe router learns from examples like:\n| Query | Technique |\n|-------|-----------|\n| \"What is this?\" | `full_low` |\n| \"Count the items\" | `preserve` |\n| \"Read the text\" | `transcode` |\n| \"What's in the corner?\" | `crop` |\n\n### Provider-Specific Compression\n\nEach provider handles images differently:\n\n| Provider | Method | Savings |\n|----------|--------|---------|\n| **OpenAI** | `detail=\"low\"` parameter | ~87% |\n| **Anthropic** | PIL resize to 512px | ~75% |\n| **Google** | PIL resize to 768px (tile-optimized) | ~75% |\n\n### Integration Points\n\nImage compression runs in the proxy **before** text compression:\n\n```\nRequest arrives\n      ↓\n[Image Compression] ← NEW\n      ↓\n[Transform Pipeline: Cache Aligner → Smart Crusher → ...]\n      ↓\nForward to LLM\n```\n\nThis ensures images are compressed first, then text compression (CCR, SmartCrusher) handles the rest.\n\n### Code Location\n\n```\nheadroom/\n├── image/\n│   ├── __init__.py         # Public API\n│   ├── compressor.py       # ImageCompressor class\n│   └── trained_router.py   # TrainedRouter (HuggingFace model)\n├── proxy/\n│   └── server.py           # Integration point\n```\n\n---\n\n## File Structure Explained\n\n```\nheadroom/\n├── __init__.py          # Public exports\n├── client.py            # HeadroomClient - the main wrapper\n├── config.py            # All configuration dataclasses\n├── parser.py            # Message → Block decomposition\n├── tokenizer.py         # Token counting abstraction\n├── utils.py             # Hashing, markers, helpers\n│\n├── providers/\n│   ├── base.py          # Provider/TokenCounter protocols\n│   ├── openai.py        # OpenAI-specific (tiktoken)\n│   └── anthropic.py     # Anthropic-specific\n│\n├── transforms/\n│   ├── base.py              # Transform protocol\n│   ├── pipeline.py          # Orchestrates all transforms\n│   ├── cache_aligner.py     # Date extraction for caching\n│   ├── smart_crusher.py     # Statistical compression (default)\n│   ├── code_compressor.py   # AST-aware code compression (tree-sitter)\n│   └── (legacy llmlingua_compressor.py removed — see [ml] extra for Kompress;\n│        rolling_window.py / intelligent_context.py / scoring.py / tool_crusher.py\n│        removed — context management is now live-zone-only)\n│\n├── cache/               # CCR Architecture - Caching & Storage\n│   ├── compression_store.py    # Phase 1: Store original content\n│   ├── compression_feedback.py # Phase 4: Learn from retrievals\n│   ├── anthropic.py     # Anthropic cache optimizer\n│   ├── openai.py        # OpenAI cache optimizer\n│   ├── google.py        # Google cache optimizer\n│   └── dynamic_detector.py # Dynamic content detection\n│\n├── ccr/                 # CCR Architecture - Tool Injection & Response Handling\n│   ├── __init__.py             # CCR module exports\n│   ├── tool_injection.py       # Phase 3: Inject retrieval tool\n│   ├── response_handler.py     # Phase 5: Handle CCR tool calls\n│   ├── context_tracker.py      # Phase 6: Multi-turn context tracking\n│   └── mcp_server.py           # MCP server for retrieval tool\n│\n├── relevance/           # Relevance scoring for compression\n│   ├── bm25.py          # BM25 keyword scorer\n│   ├── embedding.py     # Semantic embedding scorer\n│   └── hybrid.py        # Adaptive fusion scorer\n│\n├── storage/\n│   ├── base.py          # Storage protocol\n│   ├── sqlite.py        # SQLite implementation\n│   └── jsonl.py         # JSON Lines implementation\n│\n├── proxy/\n│   └── server.py        # Production HTTP proxy (CCR endpoints)\n│\n└── reporting/\n    └── generator.py     # HTML report generation\n```\n\n---\n\n## Key Design Decisions\n\n### 1. Provider-Agnostic\nWorks with ANY OpenAI-compatible API:\n- OpenAI\n- Azure OpenAI\n- Anthropic\n- Groq\n- Together\n- Local models (Ollama)\n\n### 2. Deterministic Transforms\nNo LLM calls for compression. Everything is:\n- Statistical analysis\n- Pattern matching\n- Rule-based\n\nThis means:\n- Predictable results\n- Fast (<10ms overhead)\n- No added API costs\n\n### 3. Safety First\n- Never modify user/assistant TEXT content\n- Tool call + response are atomic (drop both or neither)\n- Parse failures = no-op (return unchanged)\n- Audit mode for testing before optimizing\n\n### 4. Smart by Default\n- SmartCrusher enabled (statistical, content-aware analysis — not naive rules)\n- Conservative settings that preserve important data\n\n---\n\n## What Makes This Different?\n\n### vs. Summarization (LLM-based compression)\n| Headroom | Summarization |\n|----------|---------------|\n| Deterministic | Non-deterministic |\n| ~10ms overhead | ~2-5 seconds overhead |\n| No extra API cost | Costs money to summarize |\n| Preserves structure | Loses structure |\n| Can't hallucinate | Can hallucinate |\n\n### vs. Simple Truncation\n| Headroom | Truncation |\n|----------|------------|\n| Keeps important data | Loses end of data |\n| Statistical analysis | No analysis |\n| Detects spikes | Misses spikes |\n| Factors out constants | Keeps redundancy |\n\n---\n\n## The Numbers (From Our Tests)\n\n> **Audit note (2026-09-02):** the specific token counts previously shown here\n> (a \"5 tool call SRE incident\" example) could not be traced to any benchmark,\n> test, or committed artifact in this repo and have been removed rather than\n> replaced with another unverified figure. For sourced compression numbers see\n> [Benchmarks](benchmarks.md) / `docs/content/docs/benchmarks.mdx`.\n\nReal-world SRE incident investigation (metrics, logs, status, deployments,\nrunbook tool calls in one turn) is the kind of workload SmartCrusher targets:\nstatistical, repetitive tool output where most of the redundancy is in\nconstant fields and stable regions, not in the handful of data points (spikes,\nerrors) that actually matter to the model's answer.\n\nThe model could still:\n- Identify the CPU spike (preserved by change point detection)\n- Reference specific error rates (kept in compressed data)\n- Provide correct remediation commands\n\n---\n\n## Summary\n\n**Headroom is a Context Budget Controller that:**\n\n1. **Wraps** your existing LLM client\n2. **Analyzes** your messages to find waste\n3. **Compresses** tool outputs intelligently (not blindly)\n4. **Preserves** important information (spikes, anomalies, unique data)\n5. **Logs** everything for observability\n6. **Saves** 70-90% of tokens on tool-heavy workloads\n\n**The key insight:** Most tool output redundancy is **statistical** (repeated values, constant fields, similar messages). By analyzing the data first, we can compress intelligently without losing the information that matters.\n","isInternal":false,"tokens":9046,"sizeBytes":41682},{"name":"package-lock.json","path":"e2e/wrap/tools/package-lock.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package-lock.json","title":"Tools Skill","category":"anthropic-skill","format":"json","content":"# Tools Skill\n\nPath: `e2e/wrap/tools/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package-lock.json)","tokens":300,"sizeBytes":183},{"name":"package.json","path":"e2e/wrap/tools/package.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package.json","title":"Tools Skill","category":"anthropic-skill","format":"json","content":"# Tools Skill\n\nPath: `e2e/wrap/tools/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package.json)","tokens":300,"sizeBytes":173},{"name":"README.md","path":"headroom/evals/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/headroom/evals/README.md","title":"Evals Skill","category":"anthropic-skill","format":"markdown","content":"# Headroom Evaluation Framework\n\n**Prove that compression preserves LLM accuracy through rigorous OSS benchmarks.**\n\n## Results\n\n### Standard Benchmarks — \"No Accuracy Loss\"\n\n| Benchmark | Category | N | Baseline | Headroom | Delta |\n|-----------|----------|---|----------|----------|-------|\n| [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |\n| [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |\n\n### Compression Benchmarks — \"Big Savings, Accuracy Preserved\"\n\n| Benchmark | Category | N | Accuracy | Compression | Method |\n|-----------|----------|---|----------|-------------|--------|\n| [SQuAD v2](https://huggingface.co/datasets/rajpurkar/squad_v2) | QA | 100 | **97%** | 19% | Before/After |\n| [BFCL](https://huggingface.co/datasets/gorilla-llm/Berkeley-Function-Calling-Leaderboard) | Tool/Function | 100 | **97%** | 32% | LLM-as-Judge |\n| Tool Outputs (built-in) | Agent | 8 | **100%** | 20% | Before/After + Proxy |\n| CCR Needle Retention | Lossless | 50 | **100%** | 77% | Exact Match |\n\nModel: `gpt-4o-mini` | Suite cost: ~$3 | Duration: ~15 min\n\n## Installation\n\n```bash\npip install \"headroom-ai[all]\"    # Everything including evals (recommended)\npip install \"headroom-ai[evals]\"  # Evaluation framework only\n```\n\n## Quick Start\n\n### Run the Evaluation Suite\n\n```bash\n# Quick smoke test (8 cases, ~10s)\npython -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n\n# Full Tier 1 suite (~$3, ~15 min) — requires proxy running\npython -m headroom.evals suite --tier 1 -o eval_results/\n\n# Extended suite (Tiers 1+2, ~$8, ~1 hr)\npython -m headroom.evals suite --tier 2 -o eval_results/\n\n# CI mode — exit 1 on any regression\npython -m headroom.evals suite --tier 1 --ci\n\n# List all available datasets\npython -m headroom.evals list\n```\n\n### Running with the Proxy (Recommended)\n\nFor the most accurate evaluation, run through the Headroom proxy which provides\nthe full stack: compression + CCR retrieval + cache alignment.\n\n```bash\n# Terminal 1: Start the proxy\nheadroom proxy --port 8787\n\n# Terminal 2: Run evals (auto-detects proxy)\npython -m headroom.evals suite --tier 1 -o eval_results/\n```\n\nWithout the proxy, the eval runner falls back to local compression only (no CCR).\n\n### Python API\n\n```python\nfrom headroom.evals.suite_runner import SuiteRunner\nfrom headroom.evals.reports.report_card import save_reports\n\n# Run Tier 1 suite\nrunner = SuiteRunner(model=\"gpt-4o-mini\", tiers=[1])\nresult = runner.run()\n\n# Save Markdown, JSON, and HTML reports\nsave_reports(result, \"eval_results/\")\n```\n\n## Session Probes (real recorded sessions)\n\nThe benchmark suites above prove the compressors in vitro. Session probes\nmeasure what compression removed from YOUR real sessions, offline and with no\nLLM or API key:\n\n```bash\n# 1. Record: run the proxy with recording enabled (opt-in; recordings contain\n#    full conversation content in plaintext and stay on this machine)\nHEADROOM_PROBE_RECORD_DIR=~/.headroom/probe-recordings headroom proxy start\n\n# 2. Use your agent through the proxy as normal, then score retention:\nheadroom evals probes --recordings ~/.headroom/probe-recordings\n```\n\nProbe targets are extracted from original tool results across three\ndimensions — exact numerics, artifact trail (paths/URLs/hashes), error\nevidence — and classified as retained (verbatim or surviving a format\nconversion), recoverable (behind a CCR retrieval marker), or lost. The report\nbuckets retention by compression ratio and groups it per transform. Use\n`--json-output report.json` for machine-readable results.\n\n## Evaluation Tiers\n\n### Tier 1: Core Report Card (~$3, ~15 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| GSM8K | lm-eval harness | Math reasoning accuracy |\n| TruthfulQA | lm-eval harness | Factual accuracy |\n| MMLU | lm-eval harness | 57-subject knowledge |\n| ARC-Challenge | lm-eval harness | Science reasoning |\n| HumanEval | lm-eval harness | Code generation |\n| SQuAD v2 | Before/After | Reading comprehension with compression |\n| BFCL | LLM-as-Judge | Function calling with compressed schemas |\n| Tool Outputs | Before/After + Proxy | Agent tool output compression |\n| CCR Needle Retention | Compression-only | Lossless anomaly preservation |\n\n### Tier 2: Extended (~$5 more, ~30 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HotpotQA | Before/After | Multi-hop QA with compressed passages |\n| MS MARCO | Before/After | RAG with compressed search results |\n| CodeSearchNet | Before/After | Code understanding after compression |\n| Info Retention | Compression-only | Probe fact survival in compressed output |\n\n### Tier 3: Deep Dive (~$9 more, ~45 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HellaSwag | lm-eval harness | Commonsense reasoning |\n| NarrativeQA | Before/After | Long narrative comprehension |\n| TriviaQA | Before/After | Factoid QA at scale |\n\n## Evaluation Methods\n\n### Before/After (Default)\n\nCompares LLM responses on original vs. compressed context:\n\n```\nOriginal Context ──► LLM ──► Response A\n                                         ├─► Compare (F1, semantic sim, GT match)\nCompressed Context ──► LLM ──► Response B\n```\n\nWhen the Headroom proxy is running, the \"compressed\" path goes through the full\nstack (compression + CCR tool injection + cache alignment), which is the real\nproduction experience.\n\n### LLM-as-Judge (for BFCL, tool use)\n\nUses an LLM judge to compare the compressed response against ground truth\nsemantically. This handles cases where the same correct answer can be expressed\nin different formats (function call JSON vs natural language computation).\n\n```\nCompressed Context ──► LLM ──► Response ──► LLM Judge ──► Score 1-5\n                                                  ▲\n                                          Ground Truth\n```\n\nScore >= 3 (\"partially correct or better\") = PASS. This means the compressed\ncontext preserved enough information for the LLM to reach the right answer.\n\n### Compression-Only (Zero Cost)\n\nTests compression quality without any LLM API calls:\n- **CCR Needle Retention**: Compress JSON arrays, verify errors/anomalies survive\n- **Information Retention**: Compress and check if probe facts are preserved\n\n## Available Datasets\n\n### RAG / Retrieval\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `hotpotqa` | Multi-hop QA over multiple Wikipedia passages | 100 |\n| `natural_questions` | Real Google search questions with Wikipedia answers | 100 |\n| `triviaqa` | Large-scale trivia QA with evidence documents | 100 |\n| `msmarco` | Real Bing search queries with relevant passages | 100 |\n| `squad` | SQuAD v2 reading comprehension | 100 |\n\n### Tool Use\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `bfcl` | Berkeley Function Calling Leaderboard | 100 |\n| `toolbench` | Real-world API tool usage scenarios | 100 |\n| `tool_outputs` | Built-in realistic tool outputs (JSON, logs, etc.) | 8 |\n\n### Long Context\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `longbench` | Long context understanding (4K-128K tokens) | 50 |\n| `narrativeqa` | Story comprehension | 100 |\n\n### Code\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `codesearchnet` | Code snippets with descriptions | 100 |\n| `humaneval` | Programming problems (OpenAI) | 164 |\n\n## Metrics\n\n| Metric | Description | Pass Threshold |\n|--------|-------------|----------------|\n| F1 Score | Token overlap between responses | > 0.7 |\n| Semantic Similarity | Embedding cosine similarity | > 0.85 |\n| Ground Truth Match | Answer present in response | True |\n| LLM Judge Score | 1-5 semantic correctness scale | >= 3 |\n| Accuracy Preserved | Any of the above passes | True |\n\n## CI/CD Integration\n\n```yaml\n# .github/workflows/eval.yml\nname: Evaluation Suite\n\non:\n  pull_request:\n    paths: ['headroom/transforms/**', 'headroom/evals/**']\n  schedule:\n    - cron: '0 6 * * 1'  # Weekly\n\njobs:\n  smoke-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with: { python-version: \"3.11\" }\n      - run: pip install -e \".[all]\"\n      - name: CCR Round-trip (zero cost)\n        run: |\n          python -c \"\n          from headroom.evals.runners.compression_only import CompressionOnlyRunner\n          r = CompressionOnlyRunner()\n          result = r.evaluate_ccr_lossless(r.generate_ccr_test_cases(50))\n          assert result.passed, f'CCR failures: {result.errors}'\n          print(f'CCR: {result.passed_cases}/{result.total_cases} PASS')\n          \"\n      - name: Quick eval\n        run: python -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n        env:\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n```\n\n## Environment Variables\n\nSet in `.env` at project root (auto-loaded by the suite runner):\n\n```\nOPENAI_API_KEY=sk-...      # Required for OpenAI models\nANTHROPIC_API_KEY=sk-ant-... # Required for Anthropic models\n```\n\n## Architecture\n\n```\nheadroom/evals/\n├── __init__.py              # Public API\n├── __main__.py              # CLI (quick, list, benchmark, suite, report)\n├── core.py                  # EvalCase, EvalResult, EvalSuite\n├── datasets.py              # 12 dataset loaders (HuggingFace + built-in)\n├── metrics.py               # F1, semantic similarity, ROUGE-L, BLEU\n├── cost_tracker.py          # API spend tracking + budget enforcement\n├── suite_runner.py          # Tiered suite orchestrator (16 benchmarks)\n├── comprehensive_benchmark.py  # EleutherAI lm-eval harness wrapper\n├── runners/\n│   ├── before_after.py      # Before/After + LLM-as-Judge + proxy support\n│   └── compression_only.py  # Zero-cost CCR + info retention evals\n├── reports/\n│   └── report_card.py       # Markdown, JSON, HTML report generation\n└── memory/\n    ├── judge.py             # LLM-as-judge (OpenAI, Anthropic, LiteLLM)\n    └── runner*.py           # Memory-specific evaluation\n```\n","isInternal":false,"tokens":2600,"sizeBytes":10262},{"name":"hooks.json","path":"plugins/headroom-agent-hooks/hooks/hooks.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/hooks/hooks.json","title":"Hooks Skill","category":"anthropic-skill","format":"json","content":"# Hooks Skill\n\nPath: `plugins/headroom-agent-hooks/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/hooks/hooks.json)","tokens":300,"sizeBytes":209},{"name":"CHANGELOG.md","path":"plugins/headroom-oauth2/CHANGELOG.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-oauth2/CHANGELOG.md","title":"Headroom-oauth2 Skill","category":"anthropic-skill","format":"markdown","content":"# Changelog\n\n## 0.1.1\n\n- Inject the upstream bearer only on requests that go upstream. Local routes\n  (`/health`, `/stats*`, `/metrics`, `/v1/compress*`, `/ext/*`, …; see README)\n  are passed through untouched, so an unreachable IdP no longer 502s health\n  probes and management calls no longer mint tokens. `/p/<project>/` prefixes\n  are stripped first.\n- Startup log carries `scheme://host` of the token URL and the mint log a scope\n  count, instead of the full URL and scope list.\n- Requires `headroom-ai` ≥ 0.40 (extension middleware inside the proxy-token gate).\n\n## 0.1.0\n\nInitial release — generic OAuth2 client-credentials upstream-auth extension for the Headroom proxy.\n\n- Mints an OAuth2 client-credentials (RFC 6749 §4.4) bearer from a configurable token endpoint and\n  injects it as the upstream `Authorization` on each proxied request, via Headroom's opt-in\n  `headroom.proxy_extension` seam (`--proxy-extension oauth2`). No core changes; vendor-neutral.\n- `post` and `basic` client-auth styles; scopes, `audience`, RFC 8707 `resource`, static upstream\n  headers, configurable timeout/skew — all env-driven.\n- Token caching with single-flight refresh and pre-expiry skew; `expires_in` clamped to a positive\n  TTL.\n- Fails closed on misconfiguration; returns `502 upstream_auth_error` on mint failure without\n  leaking the IdP error body. `token_url` https-enforced (loopback exempt). Std-lib only (system\n  cert store -> works behind corporate SSL inspection).\n","isInternal":false,"tokens":371,"sizeBytes":1483},{"name":"SPEC.md","path":"plugins/headroom-oauth2/SPEC.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-oauth2/SPEC.md","title":"Headroom-oauth2 Skill","category":"anthropic-skill","format":"markdown","content":"# Spec — `headroom-oauth2` (generic OAuth2 client-credentials upstream auth)\n\n## Summary\n\nA vendor-neutral proxy extension (registers on Headroom's `headroom.proxy_extension` seam) that\nmints an OAuth2 **client-credentials** (RFC 6749 §4.4) bearer from a configured token endpoint and\ninjects it as the upstream `Authorization` on every proxied request. Lets Headroom front any\ngateway that requires a minted machine token (not a static API key) — with **zero core changes**\nand **no vendor specifics** (the gateway is entirely config/env).\n\nIt complements `#510` (env-var auth), which assumes a long-lived static key; this covers the\n\"mint-then-refresh a short-lived token\" case.\n\n## API surface (config / CLI / env)\n\nOpt-in only, via Headroom's existing flags — **no new CLI flags**:\n\n    headroom proxy --backend litellm-openai --proxy-extension oauth2\n    # or HEADROOM_PROXY_EXTENSIONS=oauth2\n\nAll configuration is env (12-factor; nothing baked in):\n\n| Env var | Required | Meaning |\n|---|---|---|\n| `HEADROOM_OAUTH2_TOKEN_URL` | yes (else no-op) | OAuth2 token endpoint; must be `https` (loopback `http` allowed for tests) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | yes | client credentials |\n| `HEADROOM_OAUTH2_SCOPES` | no | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | no | `audience` form param |\n| `HEADROOM_OAUTH2_RESOURCE` | no | RFC 8707 target `resource` form param |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | no | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | no | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | no | static upstream headers, `K=V,K2=V2` (control chars rejected) |\n| `HEADROOM_OAUTH2_TIMEOUT` / `_SKEW` | no | token request timeout / pre-expiry refresh skew (s) |\n| `HEADROOM_OAUTH2_ALLOW_INSECURE` | no | `1` to allow a non-loopback `http` token_url (discouraged) |\n\nPublic Python API: `OAuth2ClientCredentials`, `OAuth2Middleware`, `OAuth2Error`, `install`,\n`provider_from_env`, `parse_headers`.\n\n## Changes to existing behavior / defaults / compatibility\n\n- **None unless explicitly enabled.** The entry point is dormant until `--proxy-extension oauth2`\n  is passed, and even then a **no-op** unless `HEADROOM_OAUTH2_TOKEN_URL` is set.\n- When active, it **overwrites the request `Authorization` header** with the minted bearer before\n  the backend runs. The client's own `Authorization`/`x-api-key` is intentionally replaced (the\n  proxy authenticates to the gateway on the client's behalf). *Compatibility note:* because the\n  request then carries a bearer, Headroom classifies it as OAuth-mode auth — same as supplying a\n  bearer yourself; no new classification path.\n- No change to defaults, the request/response body, model routing, or compression.\n\n## User stories (Given / When / Then)\n\n- **Golden path** — *Given* a proxy started with `--proxy-extension oauth2` and valid\n  `TOKEN_URL`/`CLIENT_ID`/`CLIENT_SECRET`, *When* a client sends `/v1/messages`, *Then* the\n  extension mints (or reuses a cached) bearer and the upstream receives `Authorization: Bearer\n  <minted>` plus any static headers; the client never sees the secret.\n- **Edge: token endpoint down** — *Given* an unreachable/erroring `TOKEN_URL`, *When* a request\n  arrives, *Then* the proxy returns `502 upstream_auth_error` (no upstream call, no secret/body\n  leak) and stays up; the next request retries.\n- **Edge: wrong backend** — *Given* `--backend bedrock` (env-auth), *When* the extension installs,\n  *Then* it logs a loud warning that the injected bearer will have no effect and to use an\n  OpenAI-compatible/passthrough backend.\n\n## Failure modes & recovery\n\n| Failure | Behavior |\n|---|---|\n| Missing/invalid config at startup | `install()` raises -> proxy **fails closed** (won't start mis-auth'd) |\n| Token endpoint unreachable / non-2xx / non-JSON / no `access_token` | `OAuth2Error` -> `502`, per-request, proxy stays up, retried next request |\n| `expires_in` = 0/negative/absent | clamped to a positive TTL (never stale, never per-request mint) |\n| Concurrent first requests | single-flight lock -> exactly one mint per refresh |\n| Malformed `HEADROOM_OAUTH2_HEADERS` (CR/LF) | offending pair dropped with a warning (no header injection) |\n\n## Resilience (Docker / native / wrappers / providers / multi-process)\n\n- **Native & Docker:** identical; pure env-driven, std-lib only. Token minted via `urllib` against\n  the **system cert store**, so a corporate-injected CA is trusted with no bundled roots (works in\n  SSL-inspection networks).\n- **Wrappers (`headroom wrap`, agent hooks):** the extension lives at the proxy layer, so anything\n  routed through the proxy inherits it transparently.\n- **Providers:** effective for OpenAI-compatible / passthrough litellm backends (those that forward\n  the request bearer upstream). `bedrock`/`vertex`/`sagemaker` authenticate from env and ignore the\n  bearer -> the extension warns and is a no-op there.\n- **Multi-process (multiple workers):** the token cache is per-process; each worker mints/refreshes\n  independently. Acceptable for client-credentials (idempotent, low rate); no shared state, no\n  cross-process lock needed. Documented so operators can size token-endpoint rate limits.\n\n## Security & privacy\n\n- Secrets are env-only; **never logged** and **never returned** to the client.\n- The IdP error body is **drained, not surfaced** (may echo sensitive context).\n- `token_url` is **https-enforced** (loopback exception for tests; explicit opt-out env).\n- The minted bearer is sent only to the configured upstream; the client's inbound credential is\n  replaced, not forwarded onward.\n\n## Observability / logging / telemetry\n\n- `INFO` on install (token_url + auth style, no secrets) and on each mint (`ttl`, scopes).\n- `WARNING` on mint failure, env-auth-backend no-op, and dropped malformed static headers.\n- No metrics/telemetry emitted; piggybacks on Headroom's existing request logging. (A future\n  counter for mint/refresh/failure could be added if maintainers want it.)\n\n## Rollback / migration\n\n- **No migration** — additive and opt-in; existing deployments are unaffected.\n- **Instant rollback:** drop `--proxy-extension oauth2` (or unset `HEADROOM_PROXY_EXTENSIONS`), or\n  uninstall the package. No state to clean up, no config format changes.\n\n## Dependencies\n\n- **Runtime:** standard library only (no new core dependency). `litellm` is touched **only** if\n  `HEADROOM_OAUTH2_HEADERS` is set, and it is already a Headroom backend dependency — declared here\n  as the optional `[litellm]` extra, not a hard requirement.\n","isInternal":false,"tokens":1655,"sizeBytes":6581},{"name":"hooks.json","path":"plugins/headroom-snip/hooks/hooks.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/hooks/hooks.json","title":"Hooks Skill","category":"anthropic-skill","format":"json","content":"# Hooks Skill\n\nPath: `plugins/headroom-snip/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/hooks/hooks.json)","tokens":300,"sizeBytes":195},{"name":"tsconfig.json","path":"plugins/headroom-snip/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/tsconfig.json","title":"Headroom-snip Skill","category":"anthropic-skill","format":"json","content":"# Headroom-snip Skill\n\nPath: `plugins/headroom-snip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/tsconfig.json)","tokens":300,"sizeBytes":197},{"name":"plugin.yaml","path":"plugins/hermes/headroom_retrieve/plugin.yaml","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/headroom_retrieve/plugin.yaml","title":"Headroom_retrieve Skill","category":"anthropic-skill","format":"yaml","content":"# Headroom_retrieve Skill\n\nPath: `plugins/hermes/headroom_retrieve/plugin.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/headroom_retrieve/plugin.yaml)","tokens":300,"sizeBytes":219},{"name":"HOOK.md","path":"plugins/openclaw/hook-shim/HOOK.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/hook-shim/HOOK.md","title":"Hook-shim Skill","category":"anthropic-skill","format":"markdown","content":"# Hook-shim Skill\n\nPath: `plugins/openclaw/hook-shim/HOOK.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/hook-shim/HOOK.md)","tokens":300,"sizeBytes":191},{"name":"package-lock.json","path":"plugins/openclaw/package-lock.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package-lock.json","title":"Openclaw Skill","category":"anthropic-skill","format":"json","content":"# Openclaw Skill\n\nPath: `plugins/openclaw/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package-lock.json)","tokens":300,"sizeBytes":190},{"name":"package.json","path":"plugins/openclaw/package.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package.json","title":"Openclaw Skill","category":"anthropic-skill","format":"json","content":"# Openclaw Skill\n\nPath: `plugins/openclaw/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package.json)","tokens":300,"sizeBytes":180},{"name":"tsconfig.json","path":"plugins/openclaw/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/tsconfig.json","title":"Openclaw Skill","category":"anthropic-skill","format":"json","content":"# Openclaw Skill\n\nPath: `plugins/openclaw/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/tsconfig.json)","tokens":300,"sizeBytes":182},{"name":"package-lock.json","path":"plugins/opencode/package-lock.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package-lock.json","title":"Opencode Skill","category":"anthropic-skill","format":"json","content":"# Opencode Skill\n\nPath: `plugins/opencode/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package-lock.json)","tokens":300,"sizeBytes":190},{"name":"package.json","path":"plugins/opencode/package.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package.json","title":"Opencode Skill","category":"anthropic-skill","format":"json","content":"# Opencode Skill\n\nPath: `plugins/opencode/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package.json)","tokens":300,"sizeBytes":180},{"name":"tsconfig.json","path":"plugins/opencode/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/tsconfig.json","title":"Opencode Skill","category":"anthropic-skill","format":"json","content":"# Opencode Skill\n\nPath: `plugins/opencode/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/tsconfig.json)","tokens":300,"sizeBytes":182},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"When performing a pull request review in this repository:\r\n\r\n1. Treat `.github/PULL_REQUEST_TEMPLATE.md` and `CONTRIBUTING.md` as required policy, not optional guidance.\r\n2. Flag pull requests that do not include concrete \"Real Behavior Proof\" with environment, exact commands or steps, observed result, and what was not tested.\r\n3. Be strict about contributor verification: missing tests, missing runtime evidence, or placeholder PR text should be called out.\r\n4. For user-facing, release, dependency, workflow, or security-sensitive changes, prefer blocking feedback over optional suggestions.\r\n5. Focus on correctness, safety, and whether the PR is actually ready for human maintainer review.\r\n","isInternal":false,"tokens":138,"sizeBytes":697},{"name":"marketplace.json","path":".claude-plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/.claude-plugin/marketplace.json","title":"headroom-marketplace","category":"marketplace","format":"json","content":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    },\n    {\n      \"name\": \"headroom-snip\",\n      \"source\": \"./plugins/headroom-snip\",\n      \"description\": \"Claude Code mod: watch Headroom snip tokens off every request, with an animated band, a /headroom log and a running total.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"claude-code\",\n        \"tokens\",\n        \"compression\",\n        \"mod\"\n      ]\n    }\n  ]\n}\n","frontmatter":{"name":"headroom-marketplace","owner":{"name":"Headroom Contributors"},"metadata":{"description":"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.","version":"0.41.0"},"plugins":[{"name":"headroom","source":"./plugins/headroom-agent-hooks","description":"Headroom startup hooks for Claude Code and GitHub Copilot CLI.","version":"0.41.0","author":{"name":"Headroom Contributors","url":"https://github.com/headroomlabs-ai/headroom"},"homepage":"https://github.com/headroomlabs-ai/headroom","repository":"https://github.com/headroomlabs-ai/headroom","keywords":["headroom","hooks","claude-code","copilot-cli"]},{"name":"headroom-snip","source":"./plugins/headroom-snip","description":"Claude Code mod: watch Headroom snip tokens off every request, with an animated band, a /headroom log and a running total.","version":"0.41.0","author":{"name":"Headroom Contributors","url":"https://github.com/headroomlabs-ai/headroom"},"homepage":"https://github.com/headroomlabs-ai/headroom","repository":"https://github.com/headroomlabs-ai/headroom","keywords":["headroom","claude-code","tokens","compression","mod"]}]},"isInternal":false,"tokens":386,"sizeBytes":1468},{"name":"marketplace.json","path":".github/plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/.github/plugin/marketplace.json","title":"headroom-marketplace","category":"marketplace","format":"json","content":"{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    }\n  ]\n}\n","frontmatter":{"name":"headroom-marketplace","owner":{"name":"Headroom Contributors"},"metadata":{"description":"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.","version":"0.41.0"},"plugins":[{"name":"headroom","source":"./plugins/headroom-agent-hooks","description":"Headroom startup hooks for Claude Code and GitHub Copilot CLI.","version":"0.41.0","author":{"name":"Headroom Contributors","url":"https://github.com/headroomlabs-ai/headroom"},"homepage":"https://github.com/headroomlabs-ai/headroom","repository":"https://github.com/headroomlabs-ai/headroom","keywords":["headroom","hooks","claude-code","copilot-cli"]}]},"isInternal":false,"tokens":218,"sizeBytes":820},{"name":"README.md","path":"e2e/wrap/tools/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/README.md","title":"tools Documentation","category":"plugin-manifest","format":"markdown","content":"# tools Documentation\n\nPath: `e2e/wrap/tools/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/README.md)","tokens":300,"sizeBytes":175},{"name":"plugin.json","path":"plugins/headroom-agent-hooks/.claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":247},{"name":"plugin.json","path":"plugins/headroom-agent-hooks/.github/plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.github/plugin/plugin.json","title":"plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.github/plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.github/plugin/plugin.json)","tokens":300,"sizeBytes":240},{"name":"README.md","path":"plugins/headroom-agent-hooks/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/README.md","title":"headroom-agent-hooks Documentation","category":"plugin-manifest","format":"markdown","content":"# Headroom agent hooks\r\n\r\nThis plugin exposes lightweight startup hooks for Claude Code and GitHub Copilot CLI.\r\n\r\nThe hooks resolve and call:\n\r\n```bash\r\nheadroom init hook ensure\r\n```\r\n\r\nThat hidden helper checks for a matching durable `headroom init` deployment and starts it if needed.\n\nWhen `CLAUDE_PLUGIN_ROOT` points to a readable launcher, resolution order is\n`HEADROOM_BIN`, `headroom` on `PATH`, then `headroom` and\n`headroom.exe` in `$HOME/.local/bin`, `$HOME/.local/share/uv/tools/headroom-ai/bin`,\n`${PIPX_HOME:-$HOME/.local/pipx}/venvs/headroom-ai/bin`, `/opt/homebrew/bin`, and\n`/usr/local/bin`. If no executable is found, `HEADROOM_PYTHON`, `python3`, and\n`python` are checked for an importable `headroom` module and invoked as\n`python -m headroom.cli init hook ensure`.\n\nSet `HEADROOM_BIN` or `HEADROOM_PYTHON` to override discovery. An absent CLI emits\none actionable diagnostic and exits successfully, so the host hook remains\nnonblocking. Without a readable launcher, the hook runs bare\n`headroom init hook ensure` from `PATH` with none of the discovery above. Copilot\nCLI on Windows uses the manifest's `powershell` entry, which does the same.\n","isInternal":false,"tokens":292,"sizeBytes":1164},{"name":"README.md","path":"plugins/headroom-oauth2/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-oauth2/README.md","title":"headroom-oauth2 Documentation","category":"plugin-manifest","format":"markdown","content":"# headroom-oauth2\n\nGeneric **OAuth2 client-credentials** upstream-auth extension for the\n[Headroom](https://github.com/headroomlabs-ai/headroom) proxy.\n\nWhen Headroom routes to an OpenAI-compatible backend that is protected by an\nOAuth2 client-credentials flow (enterprise AI gateways, Azure AD / Entra, Okta,\nAuth0, Keycloak, Cognito, …), this extension mints a bearer token from a\nconfigurable token endpoint, caches + refreshes it (single-flight), and injects\n`Authorization: Bearer <token>` on each upstream request. Optional static upstream\nheaders are sent via litellm. **Fully vendor-neutral — no provider is hard-coded.**\n\nIt plugs into Headroom's public `headroom.proxy_extension` entry-point seam, so it\nis fully out-of-tree and opt-in.\n\n## Install & enable\n```bash\npip install headroom-oauth2\nheadroom proxy --backend litellm-openai --proxy-extension oauth2\n```\n\n## Configure (env; no-op unless HEADROOM_OAUTH2_TOKEN_URL is set)\n| Env | Meaning |\n|-----|---------|\n| `HEADROOM_OAUTH2_TOKEN_URL` | token endpoint (client_credentials grant) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | credentials (secrets) |\n| `HEADROOM_OAUTH2_SCOPES` | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | optional audience |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | static upstream headers, `K=V,K2=V2` |\n\nTokens are minted with the standard library (`urllib`, system cert store), which\nworks behind corporate SSL-inspection where bundled-root TLS stacks fail.\n\n\n**Effective backends:** the injected bearer reaches the upstream only for OpenAI-compatible /\npassthrough litellm providers. `bedrock` / `vertex` / `sagemaker` authenticate from env and\nignore it, so this extension is a no-op there (it logs a warning at startup).\n\n**Transport:** `token_url` must be `https` (loopback `http` is allowed for tests; set\n`HEADROOM_OAUTH2_ALLOW_INSECURE=1` to override). Tokens are minted with the standard library\n(`urllib`, system cert store), so a corporate-injected CA is trusted without bundling roots.\n\n## What gets the upstream bearer\n\nThe minted token is injected only on requests that **go upstream**. Routes the\nproxy answers itself — `/health`, `/livez`, `/readyz`, `/stats*`, `/metrics`,\n`/quota`, `/settings*`, `/dashboard*`, `/admin/*`, `/debug/*`, `/v1/compress*`,\n`/v1/usage`, `/v1/retrieve*`, `/v1/telemetry*`, `/v1/toin*`, `/v1/feedback*`,\nand any extension route under `/ext/` — are passed through untouched, so an\nunreachable IdP never turns a health probe into a 502 and management calls never\ncost a token mint. A `/p/<project>/` base-URL prefix is stripped before the\ncheck.\n\nRequires `headroom-ai` ≥ 0.40, where extension middleware runs inside the\nproxy's `HEADROOM_PROXY_TOKEN` gate: clients may then authenticate with\n`Authorization: Bearer <proxy token>` and the gate checks it before this\nextension replaces it with the upstream bearer.\n","isInternal":false,"tokens":780,"sizeBytes":3013},{"name":"plugin.json","path":"plugins/headroom-snip/.claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-snip/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":233},{"name":"README.md","path":"plugins/headroom-snip/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/README.md","title":"headroom-snip Documentation","category":"plugin-manifest","format":"markdown","content":"# headroom-snip\n\nA Claude Code mod that shows what Headroom does to each request, live. When a\nrequest goes through the proxy, a pair of scissors runs along a bar the size of\nthe original prompt, cuts it down to what was actually sent, and the token\ncount drops as it goes:\n\n```\n✂ headroom 21k → 16k   tok ━━━━━━━━━━━━━━━━━━━━━━━✂⡀⠄⠂⠁⢀⠈⠐⠠ −81%\n✂ headroom 21k → 7.6k  tok ━━━━━━━━━━━✂⠈⠐⠠⡀⠄⠂⠁⢀⠈⠐⠠⡀⠄⠂······ −81%\n✂ headroom 21k → 4.1k  tok ━━━━━━·························· −81%\n  JSON crush ×2 · Kompress text · cache align   project 184k saved (62%) over 23 req ≈ 307 pages  details  hide\n```\n\n## What it shows\n\n- **The band above the prompt.** The latest request: original → sent tokens,\n  the snip animation, and the percentage cut. Below that, which compressors did\n  the cutting (`JSON crush`, `code AST`, `Kompress text`, `log squash`,\n  `cache align`, ...) and the running total since the session started. A request sent unchanged says why,\n  for example `kept: user message, recent code` or `nothing worth a snip`.\n- **`/headroom`.** Opens a pane with the requests since the session started: one bar per\n  request, what was cut and what was protected, how long compression took, the\n  biggest snip so far, and an all-time total.\n  `/headroom hide` and `/headroom show` toggle the band.\n- **The status line.** `✂ 184k tok saved · 62%`.\n- **Milestone toasts** at 10k, 50k, 100k, 250k, 500k, 1M and 5M tokens saved.\n- **No proxy?** If nothing answers, the band says so and suggests\n  `headroom wrap claude`.\n\n## How it works\n\nWhile a turn runs, the mod polls the proxy's loopback `GET /stats?cached=1`\nonce a second. It reads the `recent_requests` tail (per-request token counts\nand `transforms_applied`), and keeps polling for a few seconds after the turn\nends. Requests stamped before the session started count as history: they\naren't animated or added to the totals, even if the proxy only comes up later.\nNothing leaves your machine.\n\nThe proxy can't tell Claude Code sessions apart, so the totals are never\nper session. What they cover depends on how Claude Code reaches the proxy:\n\n- **Through `headroom wrap claude`:** each request carries an\n  `X-Headroom-Project` header naming the launch directory (its basename, so\n  two directories with the same name share a tag). The mod counts every\n  request with this session's tag, including other sessions in the same\n  project, and leaves other projects out. The proxy only reports tags for its\n  last ten requests, so a request it can't attribute is left out rather than\n  guessed. The band says \"project\" and `/headroom` names the project.\n- **Any other way:** there is no tag, so the totals cover every client on the\n  proxy since this session started. The band says \"proxy\" and `/headroom` says\n  so.\n\nIt finds the proxy in this order:\n\n1. `HEADROOM_PROXY_URL`\n2. `ANTHROPIC_BASE_URL` (as `headroom wrap claude` sets it)\n3. `http://127.0.0.1:8787`\n\nOnly loopback URLs are used: `http` or `https` on exactly `localhost`, `127.0.0.1`\nor `[::1]`, with no user or password. A value that isn't one (a remote proxy, or a\nhost like `localhost.example.com`) is skipped, so the mod never polls a remote host.\n\n## Install\n\n```bash\nclaude plugin marketplace add headroomlabs-ai/headroom\nclaude plugin install headroom-snip@headroom-marketplace\n```\n\nOr, from a checkout: `claude --plugin-dir plugins/headroom-snip`.\n\n## Develop\n\n```bash\nclaude plugin validate plugins/headroom-snip\nclaude plugin test plugins/headroom-snip      # tests/snip.test.tsx\ntsc -p plugins/headroom-snip                  # after Claude Code has loaded it once\n```\n\n`hooks/snip.ts` holds the pure parts (parsing, transform labels, the animation\nframes) and `hooks/register.tsx` holds the hooks and drawing.\n","isInternal":false,"tokens":1087,"sizeBytes":3915},{"name":"README.md","path":"plugins/hermes/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/README.md","title":"hermes Documentation","category":"plugin-manifest","format":"markdown","content":"# hermes Documentation\n\nPath: `plugins/hermes/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/README.md)","tokens":300,"sizeBytes":176},{"name":"openclaw.plugin.json","path":"plugins/openclaw/openclaw.plugin.json","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/openclaw.plugin.json","title":"openclaw Plugin Manifest","category":"plugin-manifest","format":"json","content":"# openclaw Plugin Manifest\n\nPath: `plugins/openclaw/openclaw.plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/openclaw.plugin.json)","tokens":300,"sizeBytes":206},{"name":"README.md","path":"plugins/openclaw/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/README.md","title":"openclaw Documentation","category":"plugin-manifest","format":"markdown","content":"# openclaw Documentation\n\nPath: `plugins/openclaw/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/README.md)","tokens":300,"sizeBytes":182},{"name":"README.md","path":"plugins/opencode/README.md","rawUrl":"https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/README.md","title":"opencode Documentation","category":"plugin-manifest","format":"markdown","content":"# opencode Documentation\n\nPath: `plugins/opencode/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/README.md)","tokens":300,"sizeBytes":182}],"systemPromptSnippet":"<yakaai_skills repo=\"headroomlabs-ai/headroom\">\n<!-- File: llms.txt (Tokens: ~1642 | Category: root-instruction) -->\n# Headroom\n\n> Context optimization layer for LLM applications. Compress tool outputs, logs, files, and RAG chunks before they reach the model. Same answers, 60–95% fewer tokens. Library, proxy, and MCP server. Apache 2.0, local-first.\n\nHeadroom is shipped as a Python package (`headroom-ai`), a TypeScript package (`headroom-ai`), an OpenAI + Anthropic-compatible HTTP proxy (`headroom proxy`), and an MCP server (`headroom_compress`, `headroom_retrieve`, `headroom_stats` tools). All four modes use the same compression pipeline: per-content-type compressors (JSON, code, logs, diffs, text) feed into a Compress-Cache-Retrieve (CCR) store so compression stays reversible — the LLM can ask for the original whenever it wants.\n\nThe canonical, always-current documentation index lives at the docs site below. If you can fetch one URL, fetch that one; the entries here are a hand-curated subset.\n\n## Canonical docs (start here)\n\n- [Live llms.txt (full doc index)](https://docs.headroomlabs.ai/llms.txt): Auto-generated index of every doc page with descriptions.\n- [Live llms-full.txt (every doc page concatenated)](https://docs.headroomlabs.ai/llms-full.txt): One Markdown blob containing every doc page. Use when you can spend the tokens for full context.\n- [Docs site](https://docs.headroomlabs.ai/docs): Human-browsable docs with search.\n- [GitHub repo](https://github.com/headroomlabs-ai/headroom): Source, issues, releases.\n- [PyPI package](https://pypi.org/project/headroom-ai/): Python install.\n- [npm package](https://www.npmjs.com/package/headroom-ai): TypeScript install.\n\n## Install (copy-paste-runnable)\n\n- Python: `pip install headroom-ai` (add `[all]` for every optional extra)\n- TypeScript / Node: `npm install headroom-ai` (or `pnpm add headroom-ai`, `bun add headroom-ai`)\n- Docker local: `docker run --rm -p 127.0.0.1:8787:8787 ghcr.io/headroomlabs-ai/headroom:latest --host 0.0.0.0`\n- Run the proxy: `headroom proxy --port 8787` then point any client at `http://127.0.0.1:8787`\n- Wrap an agent in one command: `headroom wrap claude` (also: `codex`, `copilot`, `cursor`, `aider`, `opencode`, `cline`, `continue`, `goose`, `openhands`, `openclaw`, `vibe`, `omp`)\n\n## Entry points\n\n- [Quickstart](https://docs.headroomlabs.ai/docs/quickstart): 5-minute end-to-end (install → compress → call the model).\n- [Installation](https://docs.headroomlabs.ai/docs/installation): All install paths, extras, Docker tags, env vars.\n- [Proxy server](https://docs.headroomlabs.ai/docs/proxy): Run as a local HTTP proxy in front of OpenAI / Anthropic / Gemini.\n- [MCP server](https://docs.headroomlabs.ai/docs/mcp): `headroom_compress`, `headroom_retrieve`, `headroom_stats` for Claude Code / Cursor / any MCP host.\n- [API reference](https://docs.headroomlabs.ai/docs/api-reference): Python + TypeScript `compress()` API.\n\n## How it works\n\n- [How compression works](https://docs.headroomlabs.ai/docs/how-compression-works): Three-stage pipeline + automatic content routing.\n- [SmartCrusher](https://docs.headroomlabs.ai/docs/smart-crusher): Statistical JSON / array compression (70–90% on tool outputs).\n- [Code compression](https://docs.headroomlabs.ai/docs/code-compression): AST-aware via tree-sitter (preserves imports, signatures, types).\n- [Text & log compression](https://docs.headroomlabs.ai/docs/text-and-logs): Search results, build logs, diffs.\n- [CCR (reversible)](https://docs.headroomlabs.ai/docs/ccr): Compress-Cache-Retrieve — originals never deleted; LLM retrieves on demand.\n\n## SDK / framework integrations\n\n- [Anthropic SDK](https://docs.headroomlabs.ai/docs/anthropic-sdk): `withHeadroom(anthropic)` wrapper.\n- [OpenAI SDK](https://docs.headroomlabs.ai/docs/openai-sdk): `withHeadroom(openai)` wrapper.\n- [Vercel AI SDK](https://docs.headroomlabs.ai/docs/vercel-ai-sdk): Middleware + `withHeadroom()`.\n- [LangChain](https://docs.headroomlabs.ai/docs/langchain): Chat models, memory, retrievers, agents.\n- [Agno](https://docs.headroomlabs.ai/docs/agno): Model wrapping + observability hooks.\n- [Strands](https://docs.headroomlabs.ai/docs/strands): Model wrapping + hook-based tool output compression.\n- [LiteLLM](https://docs.headroomlabs.ai/docs/litellm): Single callback; works with all 100+ LiteLLM providers.\n\n## Memory & cross-agent state\n\n- [Persistent memory](https://docs.headroomlabs.ai/docs/memory): Per-project SQLite + HNSW vector store. No cross-project bleed (GH #462).\n- [SharedContext](https://docs.headroomlabs.ai/docs/shared-context): Compressed inter-agent context handoffs.\n- [Failure learning](https://docs.headroomlabs.ai/docs/failure-learning): Offline analysis writes corrections to `CLAUDE.local.md` (default, gitignored) or `CLAUDE.md` (shared) / `AGENTS.md` / `GEMINI.md`.\n\n## Operations\n\n- [Configuration](https://docs.headroomlabs.ai/docs/configuration): Env vars, config file, per-call overrides.\n- [Benchmarks](https://docs.headroomlabs.ai/docs/benchmarks): Token-savings numbers across content types.\n- [Troubleshooting](https://docs.headroomlabs.ai/docs/troubleshooting): Common failure modes and fixes.\n- [Limitations](https://docs.headroomlabs.ai/docs/limitations): What Headroom won't do well today.\n\n## Headroom for Teams\n\nFor teams and companies that want Headroom across every developer rather than one laptop: Headroom Enterprise adds more savings (tool search for every model, harness tuning, extra compressors), automatic model routing (open source has opt-in, rule-based routing), prompt-injection and risky-tool-call removal, SSO, managed or VPC deployment, an org-wide savings dashboard, and support. Companies that sign a 12-month Enterprise plan get the first 3 months free.\n\n- [Headroom for Teams](https://docs.headroomlabs.ai/docs/teams): Open source vs Enterprise, and the 3-months-free offer.\n- [Claim 3 months free](https://headroom-perks.vercel.app/?source=github&utm_source=llms-txt): Perk sign-up form. One perk per company.\n\n## Licensing\n\nApache 2.0. Use commercially, modify, redistribute. Data stays on the user's machine when running the library, proxy, or MCP server locally. An anonymous usage beacon is **on by default**: it reports compression ratios, counters, provider and model IDs, OS and architecture, and never prompts, completions, code or file paths. Turn it off with `HEADROOM_BEACON=off`, `DO_NOT_TRACK=1`, or `HEADROOM_OFFLINE=1`. See [Telemetry](https://github.com/headroomlabs-ai/headroom#telemetry).\n\n<!-- File: wiki/api.md (Tokens: ~1781 | Category: project-spec) -->\n# API Reference\n\n## HeadroomClient\n\nThe main entry point for Headroom SDK.\n\n```python\nfrom headroom import HeadroomClient\nfrom openai import OpenAI\n\nclient = HeadroomClient(\n    original_client=OpenAI(),\n    default_mode=\"optimize\",\n)\n```\n\n### Constructor Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `original_client` | `OpenAI \\| Anthropic` | Required | The underlying LLM client |\n| `provider` | `Provider` | Required (no default) | Token counting provider — e.g. `OpenAIProvider()`, `AnthropicProvider()` |\n| `default_mode` | `str` | `\"audit\"` | Default mode: \"audit\", \"optimize\", \"off\" |\n| `store_url` | `str` | `None` | Storage URL for metrics |\n| `model_context_limits` | `dict[str, int]` | `None` | Override context limits for models |\n| `cache_optimizer` | `BaseCacheOptimizer` | `None` (auto-detect) | Custom cache optimizer |\n| `enable_cache_optimizer` | `bool` | `True` | Enable provider-specific cache optimization |\n| `enable_semantic_cache` | `bool` | `False` | Enable query-level semantic caching |\n| `config` | `HeadroomConfig` | `None` | Full config object; set `config.smart_crusher` / `config.cache_aligner` here to override compression/cache-alignment settings — there is no separate `smart_crusher_config`/`cache_aligner_config` constructor kwarg |\n\n### Methods\n\n#### `chat.completions.create(**kwargs)`\n\nCreate a chat completion with optional optimization.\n\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[...],\n    headroom_mode=\"optimize\",  # Override default mode\n)\n```\n\n**Additional Parameters:**\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `headroom_mode` | `str` | Override mode for this request |\n| `headroom_query` | `str` | Query for relevance scoring |\n\n#### `chat.completions.simulate(**kwargs)`\n\nPreview optimization without making an API call.\n\n```python\nplan = client.chat.completions.simulate(\n    model=\"gpt-4o\",\n    messages=[...],\n)\n\nprint(f\"Tokens before: {plan.tokens_before}\")\nprint(f\"Tokens after: {plan.tokens_after}\")\nprint(f\"Savings: {plan.savings_percent:.1f}%\")\n```\n\n**Returns:** `SimulationResult`\n\n---\n\n## Configuration Classes\n\n### SmartCrusherConfig\n\n```python\nfrom headroom import SmartCrusherConfig\n\nconfig = SmartCrusherConfig(\n    min_tokens_to_crush=200,\n    max_items_after_crush=50,\n    keep_first=3,\n    keep_last=2,\n    relevance_threshold=0.3,\n    anomaly_std_threshold=2.0,\n    preserve_errors=True,\n)\n```\n\n### CacheAlignerConfig\n\n```python\nfrom headroom import CacheAlignerConfig\n\nconfig = CacheAlignerConfig(\n    extract_dates=True,\n    normalize_whitespace=True,\n    stable_prefix_min_tokens=100,\n)\n```\n\n### RelevanceScorerConfig\n\n```python\nfrom headroom import RelevanceScorerConfig\n\nconfig = RelevanceScorerConfig(\n    scorer_type=\"bm25\",  # \"bm25\", \"embedding\", or \"hybrid\"\n    embedding_model=None,  # Model name for embedding scorer\n    hybrid_alpha=0.5,  # Weight for hybrid scoring\n)\n```\n\n---\n\n## Data Models\n\n### SimulationResult\n\nReturned by `simulate()`.\n\n```python\n@dataclass\nclass SimulationResult:\n    tokens_before: int\n    tokens_after: int\n    tokens_saved: int\n    savings_percent: float\n    transforms_applied: list[str]\n    waste_signals: WasteSignals\n```\n\n### RequestMetrics\n\nMetrics for a single request.\n\n```python\n@dataclass\nclass RequestMetrics:\n    request_id: str\n    timestamp: datetime\n    model: str\n    tokens_input_before: int\n    tokens_input_after: int\n    tokens_output: int\n    cost_before: float\n    cost_after: float\n    transforms_applied: list[str]\n```\n\n### WasteSignals\n\nDetected waste in the request.\n\n```python\n@dataclass\nclass WasteSignals:\n    json_bloat_tokens: int\n    html_noise_tokens: int\n    whitespace_tokens: int\n    dynamic_date_tokens: int\n    repetition_tokens: int\n```\n\n---\n\n## Providers\n\n### OpenAIProvider\n\n```python\nfrom headroom import OpenAIProvider\n\nprovider = OpenAIProvider()\n\n# Get token counter\ncounter = provider.get_token_counter(\"gpt-4o\")\ntokens = counter.count_text(\"Hello, world!\")\n\n# Get context limit\nlimit = provider.get_context_limit(\"gpt-4o\")  # 128000\n\n# Estimate cost\ncost = provider.estimate_cost(\n    input_tokens=1000,\n    output_tokens=500,\n    model=\"gpt-4o\",\n)\n```\n\n### AnthropicProvider\n\n```python\nfrom headroom import AnthropicProvider\nfrom anthropic import Anthropic\n\nprovider = AnthropicProvider(client=Anthropic())\n\ncounter = provider.get_token_counter(\"claude-3-5-sonnet-latest\")\ntokens = counter.count_messages(messages)  # Accurate count via API\n```\n\n---\n\n## Relevance Scoring\n\n### BM25Scorer\n\nFast keyword-based scoring (zero dependencies).\n\n```python\nfrom headroom import BM25Scorer\n\nscorer = BM25Scorer()\nscores = scorer.score_items(\n    items=[\"item 1\", \"item 2\", ...],\n    query=\"search query\",\n)\n```\n\n### EmbeddingScorer\n\nSemantic similarity scoring (requires `sentence-transformers`).\n\n```python\nfrom headroom import EmbeddingScorer, embedding_available\n\nif embedding_available():\n    scorer = EmbeddingScorer(model=\"all-MiniLM-L6-v2\")\n    scores = scorer.score_items(items, query)\n```\n\n### HybridScorer\n\nCombines BM25 and embeddings.\n\n```python\nfrom headroom import HybridScorer\n\nscorer = HybridScorer(alpha=0.5)  # 50% BM25, 50% embedding\nscores = scorer.score_items(items, query)\n```\n\n### create_scorer()\n\nFactory function to create scorers.\n\n```python\nfrom headroom import create_scorer\n\n# Auto-select best available scorer\nscorer = create_scorer()\n\n# Explicitly choose type\nscorer = create_scorer(scorer_type=\"hybrid\", alpha=0.7)\n```\n\n---\n\n## Transforms (Direct Use)\n\n### SmartCrusher\n\n```python\nfrom headroom import SmartCrusher\n\ncrusher = SmartCrusher()\nresult = crusher.crush(\n    data={\"results\": [...]},\n    query=\"user query\",\n)\n```\n\n### CacheAligner\n\n```python\nfrom headroom import CacheAligner\n\naligner = CacheAligner()\nresult = aligner.align(messages)\n```\n\n> **Context management** is handled automatically inside the pipeline\n> (live-zone-only compression). The position-based `RollingWindow` and\n> score-based `IntelligentContextManager` / `MessageScorer` APIs have been\n> removed and are no longer part of Headroom.\n\n### TransformPipeline\n\n```python\nfrom headroom import TransformPipeline\n\npipeline = TransformPipeline(\n    [\n        SmartCrusher(),\n        CacheAligner(),\n    ]\n)\n\nresult = pipeline.transform(messages)\n```\n\n---\n\n## Utilities\n\n### Tokenizer\n\n```python\nfrom headroom import Tokenizer, count_tokens_text, count_tokens_messages\n\n# Quick counting\ntokens = count_tokens_text(\"Hello, world!\", model=\"gpt-4o\")\n\n# With tokenizer instance\ntokenizer = Tokenizer(model=\"gpt-4o\")\ntokens = tokenizer.count_text(\"Hello\")\ntokens = tokenizer.count_messages(messages)\n```\n\n### generate_report()\n\nGenerate HTML/Markdown reports from stored metrics.\n\n```python\nfrom headroom import generate_report\n\nreport = generate_report(\n    store_url=\"sqlite:///headroom.db\",\n    format=\"html\",\n    period=\"day\",\n)\n```\n\n---\n\n## TypeScript SDK\n\nFor the TypeScript SDK API reference, see [TypeScript SDK](typescript-sdk.md).\n\nThe TypeScript SDK provides `compress()`, `HeadroomClient`, and framework adapters for Vercel AI SDK, OpenAI, and Anthropic.\n\n<!-- File: wiki/ARCHITECTURE.md (Tokens: ~9046 | Category: project-spec) -->\n# Headroom SDK: A Complete Explanation\n\n## Architecture Overview\n\n```mermaid\nflowchart TB\n    subgraph Entry[\"Entry Points\"]\n        Proxy[\"Proxy Mode<br/><i>Zero code changes</i>\"]\n        SDK[\"SDK Mode<br/><i>HeadroomClient</i>\"]\n        Integrations[\"Integrations<br/><i>LangChain / Agno</i>\"]\n    end\n\n    subgraph Pipeline[\"Transform Pipeline\"]\n        direction TB\n\n        CA[\"Cache Aligner<br/>━━━━━━━━━━━━━━━<br/>Extracts dynamic content<br/>(dates, UUIDs, tokens)<br/>Stable prefix for caching\"]\n\n        SC[\"Smart Crusher<br/>━━━━━━━━━━━━━━━<br/>Analyzes tool outputs<br/>Keeps: first, last, errors, outliers<br/>70-95% reduction\"]\n\n        CM[\"Context Manager<br/>━━━━━━━━━━━━━━━<br/>Enforces token limits<br/>Scores by recency and relevance<br/>Fits context window\"]\n\n        CA --> SC --> CM\n    end\n\n    subgraph Cache[\"Provider Cache Optimization\"]\n        direction LR\n        Anthropic[\"Anthropic<br/><i>cache_control blocks</i><br/>90% savings\"]\n        OpenAI[\"OpenAI<br/><i>Prefix alignment</i><br/>50% savings\"]\n        Google[\"Google<br/><i>CachedContent API</i><br/>75% savings\"]\n    end\n\n    subgraph CCR[\"CCR: Compress-Cache-Retrieve\"]\n        Store[(\"Compression<br/>Store\")]\n        Tool[\"Retrieve Tool<br/><i>LLM requests original</i>\"]\n        Store <--> Tool\n    end\n\n    LLM[\"LLM API<br/><i>OpenAI / Anthropic / Google</i>\"]\n\n    Entry --> Pipeline\n    Pipeline --> Cache\n    Cache --> LLM\n    SC -.->|\"Stores original\"| Store\n    LLM -.->|\"If needed\"| Tool\n```\n\n---\n\n## What Problem Does Headroom Solve?\n\nWhen you use AI models like GPT-4 or Claude, you pay for **tokens** - the pieces of text you send (input) and receive (output). The problem is:\n\n1. **Tool outputs are HUGE**: When an AI agent calls tools (search, database queries, APIs), the responses are often massive JSON blobs with thousands of tokens\n2. **Most of that data is REDUNDANT**: 60 metric data points showing `cpu: 45%` repeated, or 50 log entries with the same error message\n3. **You're paying for waste**: Every token costs money and adds latency\n4. **Context windows fill up**: Models have limits (128K tokens), and bloated tool outputs eat into your available space\n\n**Headroom creates \"headroom\"** - it intelligently compresses your input tokens so you have more room (and budget) for what matters.\n\n---\n\n## How Headroom Works: The Big Picture\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                        YOUR APPLICATION                          │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                      HEADROOM CLIENT                             │\n│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │\n│  │   ANALYZE   │→ │  TRANSFORM  │→ │    CALL     │             │\n│  │  (Parser)   │  │  (Pipeline) │  │   (API)     │             │\n│  └─────────────┘  └─────────────┘  └─────────────┘             │\n│         │                │                │                     │\n│         ▼                ▼                ▼                     │\n│   Count tokens     Apply compressions   Send to OpenAI/Claude  │\n│   Detect waste     Preserve meaning     Log metrics            │\n└─────────────────────────────────────────────────────────────────┘\n                               │\n                               ▼\n┌─────────────────────────────────────────────────────────────────┐\n│                    OPENAI / ANTHROPIC API                        │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Core Components (In Simple Terms)\n\n### 1. HeadroomClient (`client.py`) - The Wrapper\n\n`HeadroomClient` is still exported (`headroom/__init__.py:93,197`), but it is\nno longer the only SDK entry point: the site's current architecture\ndocumentation (`docs/content/docs/architecture.mdx`) describes SDK mode as\ncalling the one-function `compress()` API (`headroom.compress`,\n`headroom.CompressConfig`) directly on your messages, with `HeadroomClient`\nas the client-wrapping alternative. Both exist; this section covers only the\nwrapper.\n\nThis is what you interact with. It wraps your existing OpenAI or Anthropic client:\n\n```python\n# Before (normal OpenAI)\nclient = OpenAI(api_key=\"...\")\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n\n# After (with Headroom)\nbase = OpenAI(api_key=\"...\")\nclient = HeadroomClient(original_client=base, provider=OpenAIProvider())\nresponse = client.chat.completions.create(model=\"gpt-4o\", messages=[...])\n```\n\n**What it does:**\n- Intercepts your API calls\n- Runs messages through the transform pipeline\n- Calls the real API with optimized messages\n- Logs metrics to a database\n- Returns the response unchanged\n\n**Two modes:**\n- `audit`: Just observe and log (no changes)\n- `optimize`: Apply transforms to reduce tokens\n\n---\n\n### 2. Providers (`providers/`) - Model-Specific Knowledge\n\nDifferent AI providers have different rules:\n\n```python\nclass OpenAIProvider:\n    # Knows GPT-4o has 128K context\n    # Knows how to count tokens (tiktoken)\n    # Knows pricing ($2.50 per million input tokens)\n\nclass AnthropicProvider:\n    # Knows Claude has 200K context\n    # Uses different tokenization (~4 chars per token)\n    # Different pricing structure\n```\n\n**Why this matters:** Token counting is model-specific. GPT-4 uses different tokenization than Claude. Headroom needs accurate counts to know how much to compress.\n\n---\n\n### 3. Parser (`parser.py`) - Understanding Your Messages\n\nBefore optimizing, Headroom needs to understand what's in your messages:\n\n```python\nmessages = [\n    {\"role\": \"system\", \"content\": \"You are helpful...\"},\n    {\"role\": \"user\", \"content\": \"Search for X\"},\n    {\"role\": \"assistant\", \"tool_calls\": [...]},\n    {\"role\": \"tool\", \"content\": \"{huge JSON}\"},\n]\n\n# Parser breaks this into \"blocks\":\nblocks = [\n    Block(kind=\"system\", tokens=50, ...),\n    Block(kind=\"user\", tokens=10, ...),\n    Block(kind=\"tool_call\", tokens=20, ...),\n    Block(kind=\"tool_result\", tokens=5000, ...),  # ← This is the problem!\n]\n```\n\n**It also detects waste signals:**\n- Large JSON blobs (>500 tokens)\n- HTML tags and comments\n- Base64 encoded data\n- Excessive whitespace\n\n---\n\n### 4. Transforms (`transforms/`) - The Compression Magic\n\nThis is where the real work happens. Headroom has 4 transforms that run in sequence:\n\n#### Transform 1: Cache Aligner\n\n**Problem:** LLM providers cache your prompts, but only if they're byte-identical. If your system prompt has today's date, every day is a cache miss.\n\n```python\n# Before:\n\"You are helpful. Current Date: 2024-12-15\"  # Changes daily = no cache\n\n# After:\n\"You are helpful.\"  # Static = cacheable\n\"[Context: Current Date: 2024-12-15]\"  # Dynamic part moved to end\n```\n\n**How it works:**\n1. Find date patterns in system prompt\n2. Extract them\n3. Move to end of message\n4. Now the PREFIX is stable → cache hits!\n\n---\n\n#### Transform 2: Tool Crusher (Naive) - DISABLED BY DEFAULT\n\nThis was our first approach - simple but limited:\n\n```python\n# Before: 60 items\n[{\"ts\": 1, \"cpu\": 45}, {\"ts\": 2, \"cpu\": 45}, ..., {\"ts\": 60, \"cpu\": 95}]\n\n# After: First 10 items only\n[{\"ts\": 1, \"cpu\": 45}, ..., {\"ts\": 10, \"cpu\": 45}, {\"__truncated\": 50}]\n```\n\n**Problem:** If the important data (CPU spike) is at position 45, it gets thrown away!\n\n---\n\n#### Transform 3: Smart Crusher (NEW DEFAULT)\n\nThis is the intelligent approach using **statistical analysis**:\n\n```python\n# Analyzes the data first:\nanalysis = {\n    \"ts\": {\"type\": \"sequential\", \"unique_ratio\": 1.0},\n    \"host\": {\"type\": \"constant\", \"value\": \"prod-1\"},  # ← Same everywhere!\n    \"cpu\": {\"variance\": 892, \"change_points\": [45]},  # ← Spike detected!\n}\n\n# Smart compression:\n{\n    \"__headroom_constants\": {\"host\": \"prod-1\"},  # Factor out\n    \"__headroom_summary\": \"items 0-44: cpu stable at ~45\",  # Summarize boring part\n    \"data\": [\n        {\"ts\": 45, \"cpu\": 92},  # Keep the spike!\n        {\"ts\": 46, \"cpu\": 95},\n        ...,\n    ],\n}\n```\n\n**Strategies it uses:**\n1. **TIME_SERIES**: Detect variance spikes, keep change points\n2. **CLUSTER**: Group similar log messages, keep 1-2 per cluster\n3. **TOP_N**: For search results, keep highest scored\n4. **SMART_SAMPLE**: Statistical sampling with constant extraction\n\n---\n\n#### Transform 4: ML Compressor (Optional, Kompress)\n\n**When to use:** Maximum compression needed and latency is acceptable.\n\nThe proxy ships an opt-in ML compression path backed by **Kompress**\n(ModernBERT-based token classifier). Install with `pip install\n'headroom-ai[ml]'`; see `wiki/transforms.md` for current configuration.\n\n**Note:** The earlier LLMLingua-2 integration (`--llmlingua` flag, the\n`headroom-ai[llmlingua]` extra, and the `LLMLinguaCompressor` class) was\nretired and replaced by Kompress. `pip install 'headroom-ai[llmlingua]'`\nno longer resolves; use `[ml]` instead.\n\n---\n\n#### Context Management: Live-Zone-Only Compression\n\n**Approach:** Headroom never drops messages from conversation history, and it does not do position-based or score-based context management. Context management is handled automatically inside the pipeline by compressing only the **live zone** — the newest content blocks (the latest user message and the latest tool result / tool output).\n\n```\n# The cache hot zone is NEVER mutated:\n# - System prompt\n# - Tool definitions\n# - Older conversation turns\n#\n# Only the newest content blocks are compressed (type-aware),\n# and every compression is reversible via CCR.\n```\n\n**Why this matters:** Leaving the hot zone untouched preserves provider prompt caching (e.g. Claude's cached-prefix read discount). Because only the newest blocks change, earlier turns stay byte-stable across requests and keep hitting the KV cache. Compression is type-aware (handled by ContentRouter and its compressors) and fully reversible — the LLM can call `headroom_retrieve` to restore any compressed block.\n\n---\n\n### 5. Storage (`storage/`) - Metrics Database\n\nEvery request is logged:\n\n```sql\nCREATE TABLE requests (\n    id TEXT PRIMARY KEY,\n    timestamp TEXT,\n    model TEXT,\n    mode TEXT,  -- audit or optimize\n    tokens_input_before INTEGER,  -- Before Headroom\n    tokens_input_after INTEGER,   -- After Headroom\n    tokens_saved INTEGER,         -- The win!\n    transforms_applied TEXT,      -- What we did\n    ...\n);\n```\n\nThis lets you:\n- See how much you're saving\n- Generate reports\n- Track trends over time\n\n---\n\n## The Data Flow (Step by Step)\n\nLet's trace a real request:\n\n### Step 1: You call the API\n```python\nresponse = client.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=[\n        {\"role\": \"system\", \"content\": \"You are an SRE. Date: 2024-12-15\"},\n        {\"role\": \"user\", \"content\": \"Check the metrics\"},\n        {\"role\": \"assistant\", \"tool_calls\": [...]},\n        {\"role\": \"tool\", \"content\": \"{60 metric points...}\"},  # 5000 tokens!\n        {\"role\": \"user\", \"content\": \"What's wrong?\"},\n    ],\n    headroom_mode=\"optimize\",\n)\n```\n\n### Step 2: HeadroomClient intercepts\n```python\n# In client.py:\ndef _create(self, messages, ...):\n    # 1. Parse messages into blocks\n    blocks, breakdown, waste = parse_messages(messages, tokenizer)\n    # breakdown = {\"system\": 50, \"user\": 20, \"tool_result\": 5000, ...}\n\n    # 2. Count original tokens\n    tokens_before = 5100\n```\n\n### Step 3: Transform Pipeline runs\n```python\n# In pipeline.py:\ndef apply(self, messages, ...):\n    # Transform 1: Cache Aligner\n    # - Extracts \"Date: 2024-12-15\" from system prompt\n    # - Moves to end\n\n    # Transform 2: Smart Crusher\n    # - Analyzes 60 metric points\n    # - Detects CPU spike at point 45\n    # - Compresses to 17 points (preserving spike)\n    # - Factors out constant \"host\" field\n\n    # Transform 3: Kompress ML compressor (opt-in via headroom-ai[ml])\n    # - ModernBERT-based compression on remaining long text\n    # - Auto-detects content type for optimal rate\n    # - Stores original in CCR for retrieval\n\n    # Transform 4: Rolling Window\n    # - Checks if we're under limit (we are)\n    # - No drops needed\n\n    return TransformResult(\n        messages=optimized,\n        tokens_before=5100,\n        tokens_after=1200,  # 76% reduction!\n        transforms=[\"cache_align\", \"smart_crush:1\"]\n    )\n```\n\n### Step 4: Call real API\n```python\n# In client.py:\nresponse = self._original.chat.completions.create(\n    model=\"gpt-4o\",\n    messages=optimized_messages,  # Only 1200 tokens now!\n)\n```\n\n### Step 5: Log metrics and return\n```python\n# Save to database\nmetrics = RequestMetrics(\n    tokens_input_before=5100,\n    tokens_input_after=1200,\n    tokens_saved=3900,  # 76%!\n    ...\n)\nstorage.save(metrics)\n\nreturn response  # Unchanged from API\n```\n\n---\n\n## The Smart Crusher Deep Dive\n\nThis is the most sophisticated part. Here's how it analyzes data:\n\n### Field Analysis\n```python\ndef analyze_field(key, items):\n    values = [item[key] for item in items]\n\n    return {\n        \"unique_ratio\": len(set(values)) / len(values),\n        # 0.0 = all same (constant)\n        # 1.0 = all different (unique IDs)\n        \"variance\": statistics.variance(values),  # For numbers\n        # Low = stable\n        # High = changing\n        \"change_points\": detect_spikes(values),\n        # Indices where value jumps significantly\n    }\n```\n\n### Pattern Detection\n```python\ndef detect_pattern(field_stats):\n    # Has timestamp + numeric variance? → TIME_SERIES\n    if has_timestamp and has_numeric_variance:\n        return \"time_series\"\n\n    # Has message field + level field? → LOGS\n    if has_message_field and has_level_field:\n        return \"logs\"\n\n    # Has score/rank field? → SEARCH_RESULTS\n    if has_score_field:\n        return \"search_results\"\n\n    return \"generic\"\n```\n\n### Compression Strategy\n```python\ndef compress(items, analysis):\n    if analysis.pattern == \"time_series\":\n        # Keep points around change points\n        # Summarize stable regions\n        return time_series_compress(items, analysis.change_points)\n\n    elif analysis.pattern == \"logs\":\n        # Cluster similar messages\n        # Keep 1-2 per cluster\n        return cluster_compress(items, analysis.clusters)\n\n    elif analysis.pattern == \"search_results\":\n        # Sort by score\n        # Keep top N\n        return top_n_compress(items, analysis.score_field)\n```\n\n---\n\n## CCR Architecture: Compress-Cache-Retrieve\n\n### The Key Insight\n\n> \"Prefer raw > Compaction > Summarization only when compaction no longer yields enough space. Compaction (Reversible) strips out information that is redundant because it exists in the environment—if the agent needs to read the data later, it can use a tool to retrieve it.\" — Phil Schmid, Context Engineering\n\n**The problem with traditional compression:** If we guess wrong about what's important, we've permanently lost data. The LLM might need something we threw away.\n\n**CCR's solution:** Make compression **reversible**. When SmartCrusher compresses, the original data is cached. If the LLM needs more, it can retrieve instantly.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  TOOL OUTPUT (1000 items)                                         │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  HEADROOM CCR LAYER                                               │\n│                                                                   │\n│  1. COMPRESS: Keep 20 items (errors, anomalies, relevant)        │\n│  2. CACHE: Store full 1000 items in fast local cache             │\n│  3. INJECT: Add retrieval capability to LLM context              │\n│                                                                   │\n│  \"20 items shown. Use /v1/retrieve?hash=xxx for more.\"           │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  LLM PROCESSING                                                   │\n│                                                                   │\n│  Option A: LLM solves task with 20 items → Done                  │\n│  Option B: LLM needs more → retrieves via API                    │\n│            → We fetch from cache → Return instantly              │\n└────────────────────────┬─────────────────────────────────────────┘\n                         │\n                         ▼\n┌──────────────────────────────────────────────────────────────────┐\n│  FEEDBACK LOOP                                                    │\n│                                                                   │\n│  Track: What did the LLM retrieve? What queries?                 │\n│  Learn: \"For this tool, keep items matching common queries\"      │\n│  Improve: Next compression uses learned patterns                 │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### CCR Phase 1: Compression Store\n\n**Location:** `headroom/cache/compression_store.py`\n\nWhen SmartCrusher compresses, the original content is stored for on-demand retrieval:\n\n```python\n@dataclass\nclass CompressionEntry:\n    hash: str  # 24-char SHA256 prefix for retrieval\n    original_content: str  # Full JSON before compression\n    compressed_content: str  # Compressed JSON\n    original_item_count: int\n    compressed_item_count: int\n    tool_name: str | None  # For feedback tracking\n    created_at: float\n    ttl: int = 1800  # 30 minute default (DEFAULT_CCR_TTL_SECONDS)\n```\n\n**Features:**\n- Thread-safe in-memory storage\n- TTL-based expiration (default 30 minutes; `DEFAULT_CCR_TTL_SECONDS`, override via `HEADROOM_CCR_TTL_SECONDS`)\n- LRU-style eviction when capacity reached\n- Hash-keyed retrieval that always returns the full original content\n\n**Usage:**\n```python\nstore = get_compression_store()\n\n# Store compressed content\nhash_key = store.store(\n    original=original_json,\n    compressed=compressed_json,\n    original_item_count=1000,\n    compressed_item_count=20,\n    tool_name=\"search_api\",\n)\n\n# Retrieve later (by hash; always returns the full original content)\nentry = store.retrieve(hash_key)\n```\n\n---\n\n### CCR Phase 2: Retrieval API\n\n**Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/retrieve` | POST | Retrieve original content by hash |\n| `/v1/retrieve/{hash}` | GET | Retrieve original content by hash |\n\nRetrieval is by hash only — it always returns the full original content.\n\n**Retrieval Request:**\n```json\n{\n    \"hash\": \"abc123def456...\"\n}\n```\n\n**Response:**\n```json\n{\n    \"hash\": \"abc123def456...\",\n    \"original_content\": \"[{...}, {...}, ...]\",\n    \"original_item_count\": 1000,\n    \"tool_name\": \"search_api\"\n}\n```\n\n---\n\n### CCR Phase 3: Tool Injection\n\nWhen compression happens, Headroom injects retrieval instructions into the LLM context.\n\n**Method A: System Message Injection**\n```\n## Compressed Context Available\nThe following tool outputs have been compressed. If you need more detail,\ncall the retrieve_compressed tool with the hash.\n\nAvailable: hash=abc123 (1000→20 items from search_api)\n```\n\n**Method B: MCP Tool Registration (Hybrid)**\nWhen running as MCP server, Headroom exposes retrieval as a tool:\n\n```json\n{\n    \"name\": \"headroom_retrieve\",\n    \"description\": \"Retrieve more items from compressed tool output\",\n    \"inputSchema\": {\n        \"type\": \"object\",\n        \"properties\": {\n            \"hash\": {\"type\": \"string\"}\n        },\n        \"required\": [\"hash\"]\n    }\n}\n```\n\n**Marker Injection:**\nCompressed content includes retrieval markers:\n```json\n{\n    \"__headroom_compressed\": true,\n    \"__headroom_hash\": \"abc123def456\",\n    \"__headroom_stats\": {\n        \"original_items\": 1000,\n        \"kept_items\": 20,\n        \"errors_preserved\": 5\n    },\n    \"data\": [...]\n}\n```\n\n---\n\n### CCR Phase 4: Feedback Loop\n\n**Location:** `headroom/cache/compression_feedback.py`\n\nThe feedback system learns from retrieval patterns to improve future compression.\n\n**Tracked Patterns per Tool:**\n```python\n@dataclass\nclass ToolPattern:\n    tool_name: str\n    total_compressions: int  # Times we compressed this tool\n    total_retrievals: int  # Times LLM asked for more\n    full_retrievals: int  # Retrieved everything (all retrievals — hash-only)\n    search_retrievals: int  # Legacy; always 0 (retrieval is hash-only, no search)\n    common_queries: dict[str, int]  # Legacy query-pattern frequency (no longer populated)\n    queried_fields: dict[str, int]  # Legacy queried-field frequency (no longer populated)\n```\n\n**Key Metrics:**\n- **Retrieval Rate**: `total_retrievals / total_compressions`\n  - High (>50%) → Compressing too aggressively\n  - Low (<20%) → Compression is effective\n- **Full Retrieval Rate**: `full_retrievals / total_retrievals`\n  - High (>80%) → Data is unique, consider skipping compression\n\n**Compression Hints:**\n```python\n@dataclass\nclass CompressionHints:\n    max_items: int = 15  # Target item count\n    suggested_items: int | None  # Calculated optimal\n    skip_compression: bool  # Don't compress at all\n    preserve_fields: list[str]  # Always keep these fields\n    aggressiveness: float  # 0.0 = aggressive, 1.0 = conservative\n    reason: str  # Explanation\n```\n\n**Feedback-Driven Adjustment:**\n```python\n# In SmartCrusher._crush_array()\nif self.config.use_feedback_hints and tool_name:\n    feedback = get_compression_feedback()\n    hints = feedback.get_compression_hints(tool_name)\n\n    if hints.skip_compression:\n        return items, f\"skip:feedback({hints.reason})\", None\n\n    if hints.suggested_items is not None:\n        self.config.max_items_after_crush = hints.suggested_items\n```\n\n**Feedback Endpoints:**\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/v1/feedback` | GET | Get all learned patterns |\n| `/v1/feedback/{tool_name}` | GET | Get hints for specific tool |\n\n**Example Response:**\n```json\n{\n    \"total_compressions\": 150,\n    \"total_retrievals\": 23,\n    \"global_retrieval_rate\": 0.15,\n    \"tools_tracked\": 5,\n    \"tool_patterns\": {\n        \"search_api\": {\n            \"compressions\": 50,\n            \"retrievals\": 5,\n            \"retrieval_rate\": 0.10,\n            \"full_rate\": 0.20,\n            \"search_rate\": 0.80,\n            \"common_queries\": [\"status:error\", \"level:critical\"],\n            \"queried_fields\": [\"status\", \"level\", \"message\"]\n        }\n    }\n}\n```\n\n---\n\n### CCR Phase 5: Response Handler (Automatic Tool Call Handling)\n\n**Location:** `headroom/ccr/response_handler.py`\n\n**The Problem:** When the proxy injects the `headroom_retrieve` tool, the LLM might call it. But who handles that tool call? Without response handling, the tool call would go back to the client unhandled.\n\n**The Solution:** The Response Handler intercepts LLM responses, detects CCR tool calls, executes retrievals automatically, and continues the conversation until the LLM produces a final response.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  RESPONSE HANDLER FLOW                                           │\n│                                                                   │\n│  1. LLM Response arrives                                         │\n│     └─ Contains: tool_use(headroom_retrieve, hash=abc123)       │\n│                                                                   │\n│  2. Handler detects CCR tool call                                │\n│     └─ Extracts hash                                             │\n│                                                                   │\n│  3. Handler executes retrieval                                   │\n│     └─ By hash: store.retrieve(hash) → full original content    │\n│                                                                   │\n│  4. Handler continues conversation                               │\n│     └─ Adds tool result to messages                             │\n│     └─ Makes another API call                                   │\n│                                                                   │\n│  5. Repeat until no CCR tool calls                              │\n│     └─ Max 3 rounds (configurable)                              │\n│                                                                   │\n│  6. Return final response to client                             │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CCRToolCall:\n    tool_call_id: str  # For matching response\n    hash_key: str  # CCR hash to retrieve\n\n\n@dataclass\nclass CCRToolResult:\n    tool_call_id: str\n    content: str  # Retrieved data as JSON\n    success: bool\n    items_retrieved: int\n\n\nclass CCRResponseHandler:\n    async def handle_response(\n        self,\n        response: dict,  # Initial LLM response\n        messages: list,  # Conversation history\n        tools: list,  # Tool definitions\n        api_call_fn: Callable,  # Function to make API calls\n        provider: str,  # \"anthropic\" or \"openai\"\n    ) -> dict:\n        \"\"\"Handle CCR tool calls until final response.\"\"\"\n```\n\n**Streaming Support:**\n\nThe handler also supports streaming responses via `StreamingCCRHandler`:\n\n```python\nclass StreamingCCRBuffer:\n    \"\"\"Buffers streaming chunks to detect CCR tool calls.\"\"\"\n\n    chunks: list[bytes]\n    detected_ccr: bool\n\n\nclass StreamingCCRHandler:\n    \"\"\"Handles CCR in streaming responses.\"\"\"\n\n    async def process_stream(self, stream, messages, tools, api_call_fn):\n        \"\"\"Yields chunks, switching to buffered mode if CCR detected.\"\"\"\n```\n\n---\n\n### CCR Phase 6: Context Tracker (Multi-Turn Awareness)\n\n**Location:** `headroom/ccr/context_tracker.py`\n\n**The Problem:** In multi-turn conversations, earlier compressed data might become relevant later. Without tracking, the LLM has \"context amnesia\" - it can't reference data that was compressed in turn 1 when answering a question in turn 5.\n\n**The Solution:** The Context Tracker maintains awareness of all compressed content across the conversation and can proactively expand relevant data when a new query might need it.\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│  CONTEXT TRACKER FLOW                                            │\n│                                                                   │\n│  Turn 1: Search returns 100 files → compressed to 10            │\n│          Tracker stores: hash=abc123, sample=\"auth.py, db.py\"   │\n│                                                                   │\n│  Turn 5: User asks \"What about the authentication middleware?\"  │\n│          Tracker analyzes query:                                 │\n│          - \"authentication\" matches \"auth.py\" in sample         │\n│          - Relevance score: 0.7 (above threshold)               │\n│                                                                   │\n│  Proactive Expansion:                                           │\n│          - Retrieves abc123 before LLM responds                 │\n│          - Adds expanded context to request                     │\n│                                                                   │\n│  Result: LLM sees full file list, can answer accurately         │\n└──────────────────────────────────────────────────────────────────┘\n```\n\n**Key Classes:**\n\n```python\n@dataclass\nclass CompressedContext:\n    hash_key: str              # CCR hash\n    turn_number: int           # When compression happened\n    timestamp: float           # For age-based filtering\n    tool_name: str | None      # Which tool was compressed\n    original_item_count: int\n    compressed_item_count: int\n    query_context: str         # User query at compression time\n    sample_content: str        # Preview for relevance matching\n\n@dataclass\nclass ExpansionRecommendation:\n    hash_key: str\n    reason: str                # Human-readable explanation\n    relevance_score: float     # 0-1, higher = more relevant\n    # Expansion always restores the full original content (retrieval is by hash).\n\nclass ContextTracker:\n    def track_compression(self, hash_key, turn_number, ...):\n        \"\"\"Track a compression event.\"\"\"\n\n    def analyze_query(self, query: str) -> list[ExpansionRecommendation]:\n        \"\"\"Find relevant compressed contexts for a query.\"\"\"\n\n    def execute_expansions(self, recommendations) -> list[dict]:\n        \"\"\"Execute recommended expansions.\"\"\"\n```\n\n**Relevance Calculation:**\n\nThe tracker uses simple but effective heuristics:\n\n1. **Keyword overlap with sample content** - Extract keywords from query, match against compressed content preview\n2. **Keyword overlap with original query** - Match against the query that triggered compression\n3. **Tool name relevance** - File operations more likely to need expansion for \"file\", \"where\", \"find\" queries\n4. **Age discount** - Older contexts get lower scores\n\n**Configuration:**\n\n```python\n@dataclass\nclass ContextTrackerConfig:\n    enabled: bool = True\n    max_tracked_contexts: int = 100  # LRU eviction\n    relevance_threshold: float = 0.3  # Min score to recommend\n    max_context_age_seconds: float = 300  # 5 minutes\n    proactive_expansion: bool = True\n    max_proactive_expansions: int = 2  # Per query\n```\n\n---\n\n### Why CCR is a Moat\n\n1. **Reversible**: No permanent information loss. Worst case = retrieve everything.\n2. **Transparent**: LLM knows it can ask for more data.\n3. **Automatic**: Response Handler executes retrievals without client intervention.\n4. **Context-Aware**: Context Tracker prevents multi-turn amnesia.\n5. **Feedback Loop**: Learn from actual needs, not guesses.\n6. **Network Effect**: Retrieval patterns across users improve compression for everyone.\n7. **Zero-Risk**: If compression fails, instant fallback to original data.\n\n---\n\n## Image Compression Architecture\n\nVision models charge by the token, and images are expensive (765-2900 tokens for a typical image). Headroom's image compression uses a **trained ML router** to automatically select the optimal compression technique.\n\n### The Key Insight\n\nNot all image queries need full resolution:\n- \"What is this?\" → Low detail is fine (87% savings)\n- \"Count the whiskers\" → Need full detail (0% savings)\n- \"Read the sign\" → Could convert to text (99% savings)\n\n### How It Works\n\n```\nUser: [image] + \"What animal is this?\"\n           ↓\n┌─────────────────────────────────┐\n│  1. Query Analysis              │\n│  TrainedRouter (MiniLM)         │\n│  Classifies → full_low          │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  2. Image Analysis (Optional)   │\n│  SigLIP checks:                 │\n│  - Has text? Is complex?        │\n│  - Fine details needed?         │\n└─────────────────────────────────┘\n           ↓\n┌─────────────────────────────────┐\n│  3. Apply Compression           │\n│  OpenAI: detail=\"low\"           │\n│  Anthropic: Resize to 512px     │\n│  Google: Resize to 768px        │\n└─────────────────────────────────┘\n           ↓\nCompressed request → LLM → Response\n```\n\n### The Trained Router\n\nA fine-tuned MiniLM classifier hosted on HuggingFace:\n\n- **Model**: `chopratejas/technique-router`\n- **Size**: ~128MB (downloaded once, cached)\n- **Accuracy**: 93.7% on 1,157 training examples\n- **Latency**: ~10ms CPU, ~2ms GPU\n\nThe router learns from examples like:\n| Query | Technique |\n|-------|-----------|\n| \"What is this?\" | `full_low` |\n| \"Count the items\" | `preserve` |\n| \"Read the text\" | `transcode` |\n| \"What's in the corner?\" | `crop` |\n\n### Provider-Specific Compression\n\nEach provider handles images differently:\n\n| Provider | Method | Savings |\n|----------|--------|---------|\n| **OpenAI** | `detail=\"low\"` parameter | ~87% |\n| **Anthropic** | PIL resize to 512px | ~75% |\n| **Google** | PIL resize to 768px (tile-optimized) | ~75% |\n\n### Integration Points\n\nImage compression runs in the proxy **before** text compression:\n\n```\nRequest arrives\n      ↓\n[Image Compression] ← NEW\n      ↓\n[Transform Pipeline: Cache Aligner → Smart Crusher → ...]\n      ↓\nForward to LLM\n```\n\nThis ensures images are compressed first, then text compression (CCR, SmartCrusher) handles the rest.\n\n### Code Location\n\n```\nheadroom/\n├── image/\n│   ├── __init__.py         # Public API\n│   ├── compressor.py       # ImageCompressor class\n│   └── trained_router.py   # TrainedRouter (HuggingFace model)\n├── proxy/\n│   └── server.py           # Integration point\n```\n\n---\n\n## File Structure Explained\n\n```\nheadroom/\n├── __init__.py          # Public exports\n├── client.py            # HeadroomClient - the main wrapper\n├── config.py            # All configuration dataclasses\n├── parser.py            # Message → Block decomposition\n├── tokenizer.py         # Token counting abstraction\n├── utils.py             # Hashing, markers, helpers\n│\n├── providers/\n│   ├── base.py          # Provider/TokenCounter protocols\n│   ├── openai.py        # OpenAI-specific (tiktoken)\n│   └── anthropic.py     # Anthropic-specific\n│\n├── transforms/\n│   ├── base.py              # Transform protocol\n│   ├── pipeline.py          # Orchestrates all transforms\n│   ├── cache_aligner.py     # Date extraction for caching\n│   ├── smart_crusher.py     # Statistical compression (default)\n│   ├── code_compressor.py   # AST-aware code compression (tree-sitter)\n│   └── (legacy llmlingua_compressor.py removed — see [ml] extra for Kompress;\n│        rolling_window.py / intelligent_context.py / scoring.py / tool_crusher.py\n│        removed — context management is now live-zone-only)\n│\n├── cache/               # CCR Architecture - Caching & Storage\n│   ├── compression_store.py    # Phase 1: Store original content\n│   ├── compression_feedback.py # Phase 4: Learn from retrievals\n│   ├── anthropic.py     # Anthropic cache optimizer\n│   ├── openai.py        # OpenAI cache optimizer\n│   ├── google.py        # Google cache optimizer\n│   └── dynamic_detector.py # Dynamic content detection\n│\n├── ccr/                 # CCR Architecture - Tool Injection & Response Handling\n│   ├── __init__.py             # CCR module exports\n│   ├── tool_injection.py       # Phase 3: Inject retrieval tool\n│   ├── response_handler.py     # Phase 5: Handle CCR tool calls\n│   ├── context_tracker.py      # Phase 6: Multi-turn context tracking\n│   └── mcp_server.py           # MCP server for retrieval tool\n│\n├── relevance/           # Relevance scoring for compression\n│   ├── bm25.py          # BM25 keyword scorer\n│   ├── embedding.py     # Semantic embedding scorer\n│   └── hybrid.py        # Adaptive fusion scorer\n│\n├── storage/\n│   ├── base.py          # Storage protocol\n│   ├── sqlite.py        # SQLite implementation\n│   └── jsonl.py         # JSON Lines implementation\n│\n├── proxy/\n│   └── server.py        # Production HTTP proxy (CCR endpoints)\n│\n└── reporting/\n    └── generator.py     # HTML report generation\n```\n\n---\n\n## Key Design Decisions\n\n### 1. Provider-Agnostic\nWorks with ANY OpenAI-compatible API:\n- OpenAI\n- Azure OpenAI\n- Anthropic\n- Groq\n- Together\n- Local models (Ollama)\n\n### 2. Deterministic Transforms\nNo LLM calls for compression. Everything is:\n- Statistical analysis\n- Pattern matching\n- Rule-based\n\nThis means:\n- Predictable results\n- Fast (<10ms overhead)\n- No added API costs\n\n### 3. Safety First\n- Never modify user/assistant TEXT content\n- Tool call + response are atomic (drop both or neither)\n- Parse failures = no-op (return unchanged)\n- Audit mode for testing before optimizing\n\n### 4. Smart by Default\n- SmartCrusher enabled (statistical, content-aware analysis — not naive rules)\n- Conservative settings that preserve important data\n\n---\n\n## What Makes This Different?\n\n### vs. Summarization (LLM-based compression)\n| Headroom | Summarization |\n|----------|---------------|\n| Deterministic | Non-deterministic |\n| ~10ms overhead | ~2-5 seconds overhead |\n| No extra API cost | Costs money to summarize |\n| Preserves structure | Loses structure |\n| Can't hallucinate | Can hallucinate |\n\n### vs. Simple Truncation\n| Headroom | Truncation |\n|----------|------------|\n| Keeps important data | Loses end of data |\n| Statistical analysis | No analysis |\n| Detects spikes | Misses spikes |\n| Factors out constants | Keeps redundancy |\n\n---\n\n## The Numbers (From Our Tests)\n\n> **Audit note (2026-09-02):** the specific token counts previously shown here\n> (a \"5 tool call SRE incident\" example) could not be traced to any benchmark,\n> test, or committed artifact in this repo and have been removed rather than\n> replaced with another unverified figure. For sourced compression numbers see\n> [Benchmarks](benchmarks.md) / `docs/content/docs/benchmarks.mdx`.\n\nReal-world SRE incident investigation (metrics, logs, status, deployments,\nrunbook tool calls in one turn) is the kind of workload SmartCrusher targets:\nstatistical, repetitive tool output where most of the redundancy is in\nconstant fields and stable regions, not in the handful of data points (spikes,\nerrors) that actually matter to the model's answer.\n\nThe model could still:\n- Identify the CPU spike (preserved by change point detection)\n- Reference specific error rates (kept in compressed data)\n- Provide correct remediation commands\n\n---\n\n## Summary\n\n**Headroom is a Context Budget Controller that:**\n\n1. **Wraps** your existing LLM client\n2. **Analyzes** your messages to find waste\n3. **Compresses** tool outputs intelligently (not blindly)\n4. **Preserves** important information (spikes, anomalies, unique data)\n5. **Logs** everything for observability\n6. **Saves** 70-90% of tokens on tool-heavy workloads\n\n**The key insight:** Most tool output redundancy is **statistical** (repeated values, constant fields, similar messages). By analyzing the data first, we can compress intelligently without losing the information that matters.\n\n<!-- File: e2e/wrap/tools/package-lock.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Tools Skill\n\nPath: `e2e/wrap/tools/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package-lock.json)\n\n<!-- File: e2e/wrap/tools/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Tools Skill\n\nPath: `e2e/wrap/tools/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/package.json)\n\n<!-- File: headroom/evals/README.md (Tokens: ~2600 | Category: anthropic-skill) -->\n# Headroom Evaluation Framework\n\n**Prove that compression preserves LLM accuracy through rigorous OSS benchmarks.**\n\n## Results\n\n### Standard Benchmarks — \"No Accuracy Loss\"\n\n| Benchmark | Category | N | Baseline | Headroom | Delta |\n|-----------|----------|---|----------|----------|-------|\n| [GSM8K](https://huggingface.co/datasets/openai/gsm8k) | Math | 100 | 0.870 | 0.870 | **0.000** |\n| [TruthfulQA](https://huggingface.co/datasets/truthfulqa/truthful_qa) | Factual | 100 | 0.530 | 0.560 | **+0.030** |\n\n### Compression Benchmarks — \"Big Savings, Accuracy Preserved\"\n\n| Benchmark | Category | N | Accuracy | Compression | Method |\n|-----------|----------|---|----------|-------------|--------|\n| [SQuAD v2](https://huggingface.co/datasets/rajpurkar/squad_v2) | QA | 100 | **97%** | 19% | Before/After |\n| [BFCL](https://huggingface.co/datasets/gorilla-llm/Berkeley-Function-Calling-Leaderboard) | Tool/Function | 100 | **97%** | 32% | LLM-as-Judge |\n| Tool Outputs (built-in) | Agent | 8 | **100%** | 20% | Before/After + Proxy |\n| CCR Needle Retention | Lossless | 50 | **100%** | 77% | Exact Match |\n\nModel: `gpt-4o-mini` | Suite cost: ~$3 | Duration: ~15 min\n\n## Installation\n\n```bash\npip install \"headroom-ai[all]\"    # Everything including evals (recommended)\npip install \"headroom-ai[evals]\"  # Evaluation framework only\n```\n\n## Quick Start\n\n### Run the Evaluation Suite\n\n```bash\n# Quick smoke test (8 cases, ~10s)\npython -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n\n# Full Tier 1 suite (~$3, ~15 min) — requires proxy running\npython -m headroom.evals suite --tier 1 -o eval_results/\n\n# Extended suite (Tiers 1+2, ~$8, ~1 hr)\npython -m headroom.evals suite --tier 2 -o eval_results/\n\n# CI mode — exit 1 on any regression\npython -m headroom.evals suite --tier 1 --ci\n\n# List all available datasets\npython -m headroom.evals list\n```\n\n### Running with the Proxy (Recommended)\n\nFor the most accurate evaluation, run through the Headroom proxy which provides\nthe full stack: compression + CCR retrieval + cache alignment.\n\n```bash\n# Terminal 1: Start the proxy\nheadroom proxy --port 8787\n\n# Terminal 2: Run evals (auto-detects proxy)\npython -m headroom.evals suite --tier 1 -o eval_results/\n```\n\nWithout the proxy, the eval runner falls back to local compression only (no CCR).\n\n### Python API\n\n```python\nfrom headroom.evals.suite_runner import SuiteRunner\nfrom headroom.evals.reports.report_card import save_reports\n\n# Run Tier 1 suite\nrunner = SuiteRunner(model=\"gpt-4o-mini\", tiers=[1])\nresult = runner.run()\n\n# Save Markdown, JSON, and HTML reports\nsave_reports(result, \"eval_results/\")\n```\n\n## Session Probes (real recorded sessions)\n\nThe benchmark suites above prove the compressors in vitro. Session probes\nmeasure what compression removed from YOUR real sessions, offline and with no\nLLM or API key:\n\n```bash\n# 1. Record: run the proxy with recording enabled (opt-in; recordings contain\n#    full conversation content in plaintext and stay on this machine)\nHEADROOM_PROBE_RECORD_DIR=~/.headroom/probe-recordings headroom proxy start\n\n# 2. Use your agent through the proxy as normal, then score retention:\nheadroom evals probes --recordings ~/.headroom/probe-recordings\n```\n\nProbe targets are extracted from original tool results across three\ndimensions — exact numerics, artifact trail (paths/URLs/hashes), error\nevidence — and classified as retained (verbatim or surviving a format\nconversion), recoverable (behind a CCR retrieval marker), or lost. The report\nbuckets retention by compression ratio and groups it per transform. Use\n`--json-output report.json` for machine-readable results.\n\n## Evaluation Tiers\n\n### Tier 1: Core Report Card (~$3, ~15 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| GSM8K | lm-eval harness | Math reasoning accuracy |\n| TruthfulQA | lm-eval harness | Factual accuracy |\n| MMLU | lm-eval harness | 57-subject knowledge |\n| ARC-Challenge | lm-eval harness | Science reasoning |\n| HumanEval | lm-eval harness | Code generation |\n| SQuAD v2 | Before/After | Reading comprehension with compression |\n| BFCL | LLM-as-Judge | Function calling with compressed schemas |\n| Tool Outputs | Before/After + Proxy | Agent tool output compression |\n| CCR Needle Retention | Compression-only | Lossless anomaly preservation |\n\n### Tier 2: Extended (~$5 more, ~30 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HotpotQA | Before/After | Multi-hop QA with compressed passages |\n| MS MARCO | Before/After | RAG with compressed search results |\n| CodeSearchNet | Before/After | Code understanding after compression |\n| Info Retention | Compression-only | Probe fact survival in compressed output |\n\n### Tier 3: Deep Dive (~$9 more, ~45 min)\n\n| Benchmark | Runner | What It Tests |\n|-----------|--------|---------------|\n| HellaSwag | lm-eval harness | Commonsense reasoning |\n| NarrativeQA | Before/After | Long narrative comprehension |\n| TriviaQA | Before/After | Factoid QA at scale |\n\n## Evaluation Methods\n\n### Before/After (Default)\n\nCompares LLM responses on original vs. compressed context:\n\n```\nOriginal Context ──► LLM ──► Response A\n                                         ├─► Compare (F1, semantic sim, GT match)\nCompressed Context ──► LLM ──► Response B\n```\n\nWhen the Headroom proxy is running, the \"compressed\" path goes through the full\nstack (compression + CCR tool injection + cache alignment), which is the real\nproduction experience.\n\n### LLM-as-Judge (for BFCL, tool use)\n\nUses an LLM judge to compare the compressed response against ground truth\nsemantically. This handles cases where the same correct answer can be expressed\nin different formats (function call JSON vs natural language computation).\n\n```\nCompressed Context ──► LLM ──► Response ──► LLM Judge ──► Score 1-5\n                                                  ▲\n                                          Ground Truth\n```\n\nScore >= 3 (\"partially correct or better\") = PASS. This means the compressed\ncontext preserved enough information for the LLM to reach the right answer.\n\n### Compression-Only (Zero Cost)\n\nTests compression quality without any LLM API calls:\n- **CCR Needle Retention**: Compress JSON arrays, verify errors/anomalies survive\n- **Information Retention**: Compress and check if probe facts are preserved\n\n## Available Datasets\n\n### RAG / Retrieval\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `hotpotqa` | Multi-hop QA over multiple Wikipedia passages | 100 |\n| `natural_questions` | Real Google search questions with Wikipedia answers | 100 |\n| `triviaqa` | Large-scale trivia QA with evidence documents | 100 |\n| `msmarco` | Real Bing search queries with relevant passages | 100 |\n| `squad` | SQuAD v2 reading comprehension | 100 |\n\n### Tool Use\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `bfcl` | Berkeley Function Calling Leaderboard | 100 |\n| `toolbench` | Real-world API tool usage scenarios | 100 |\n| `tool_outputs` | Built-in realistic tool outputs (JSON, logs, etc.) | 8 |\n\n### Long Context\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `longbench` | Long context understanding (4K-128K tokens) | 50 |\n| `narrativeqa` | Story comprehension | 100 |\n\n### Code\n\n| Dataset | Description | Default N |\n|---------|-------------|-----------|\n| `codesearchnet` | Code snippets with descriptions | 100 |\n| `humaneval` | Programming problems (OpenAI) | 164 |\n\n## Metrics\n\n| Metric | Description | Pass Threshold |\n|--------|-------------|----------------|\n| F1 Score | Token overlap between responses | > 0.7 |\n| Semantic Similarity | Embedding cosine similarity | > 0.85 |\n| Ground Truth Match | Answer present in response | True |\n| LLM Judge Score | 1-5 semantic correctness scale | >= 3 |\n| Accuracy Preserved | Any of the above passes | True |\n\n## CI/CD Integration\n\n```yaml\n# .github/workflows/eval.yml\nname: Evaluation Suite\n\non:\n  pull_request:\n    paths: ['headroom/transforms/**', 'headroom/evals/**']\n  schedule:\n    - cron: '0 6 * * 1'  # Weekly\n\njobs:\n  smoke-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with: { python-version: \"3.11\" }\n      - run: pip install -e \".[all]\"\n      - name: CCR Round-trip (zero cost)\n        run: |\n          python -c \"\n          from headroom.evals.runners.compression_only import CompressionOnlyRunner\n          r = CompressionOnlyRunner()\n          result = r.evaluate_ccr_lossless(r.generate_ccr_test_cases(50))\n          assert result.passed, f'CCR failures: {result.errors}'\n          print(f'CCR: {result.passed_cases}/{result.total_cases} PASS')\n          \"\n      - name: Quick eval\n        run: python -m headroom.evals quick -n 8 --provider openai --model gpt-4o-mini\n        env:\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n```\n\n## Environment Variables\n\nSet in `.env` at project root (auto-loaded by the suite runner):\n\n```\nOPENAI_API_KEY=sk-...      # Required for OpenAI models\nANTHROPIC_API_KEY=sk-ant-... # Required for Anthropic models\n```\n\n## Architecture\n\n```\nheadroom/evals/\n├── __init__.py              # Public API\n├── __main__.py              # CLI (quick, list, benchmark, suite, report)\n├── core.py                  # EvalCase, EvalResult, EvalSuite\n├── datasets.py              # 12 dataset loaders (HuggingFace + built-in)\n├── metrics.py               # F1, semantic similarity, ROUGE-L, BLEU\n├── cost_tracker.py          # API spend tracking + budget enforcement\n├── suite_runner.py          # Tiered suite orchestrator (16 benchmarks)\n├── comprehensive_benchmark.py  # EleutherAI lm-eval harness wrapper\n├── runners/\n│   ├── before_after.py      # Before/After + LLM-as-Judge + proxy support\n│   └── compression_only.py  # Zero-cost CCR + info retention evals\n├── reports/\n│   └── report_card.py       # Markdown, JSON, HTML report generation\n└── memory/\n    ├── judge.py             # LLM-as-judge (OpenAI, Anthropic, LiteLLM)\n    └── runner*.py           # Memory-specific evaluation\n```\n\n<!-- File: plugins/headroom-agent-hooks/hooks/hooks.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Hooks Skill\n\nPath: `plugins/headroom-agent-hooks/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/hooks/hooks.json)\n\n<!-- File: plugins/headroom-oauth2/CHANGELOG.md (Tokens: ~371 | Category: anthropic-skill) -->\n# Changelog\n\n## 0.1.1\n\n- Inject the upstream bearer only on requests that go upstream. Local routes\n  (`/health`, `/stats*`, `/metrics`, `/v1/compress*`, `/ext/*`, …; see README)\n  are passed through untouched, so an unreachable IdP no longer 502s health\n  probes and management calls no longer mint tokens. `/p/<project>/` prefixes\n  are stripped first.\n- Startup log carries `scheme://host` of the token URL and the mint log a scope\n  count, instead of the full URL and scope list.\n- Requires `headroom-ai` ≥ 0.40 (extension middleware inside the proxy-token gate).\n\n## 0.1.0\n\nInitial release — generic OAuth2 client-credentials upstream-auth extension for the Headroom proxy.\n\n- Mints an OAuth2 client-credentials (RFC 6749 §4.4) bearer from a configurable token endpoint and\n  injects it as the upstream `Authorization` on each proxied request, via Headroom's opt-in\n  `headroom.proxy_extension` seam (`--proxy-extension oauth2`). No core changes; vendor-neutral.\n- `post` and `basic` client-auth styles; scopes, `audience`, RFC 8707 `resource`, static upstream\n  headers, configurable timeout/skew — all env-driven.\n- Token caching with single-flight refresh and pre-expiry skew; `expires_in` clamped to a positive\n  TTL.\n- Fails closed on misconfiguration; returns `502 upstream_auth_error` on mint failure without\n  leaking the IdP error body. `token_url` https-enforced (loopback exempt). Std-lib only (system\n  cert store -> works behind corporate SSL inspection).\n\n<!-- File: plugins/headroom-oauth2/SPEC.md (Tokens: ~1655 | Category: anthropic-skill) -->\n# Spec — `headroom-oauth2` (generic OAuth2 client-credentials upstream auth)\n\n## Summary\n\nA vendor-neutral proxy extension (registers on Headroom's `headroom.proxy_extension` seam) that\nmints an OAuth2 **client-credentials** (RFC 6749 §4.4) bearer from a configured token endpoint and\ninjects it as the upstream `Authorization` on every proxied request. Lets Headroom front any\ngateway that requires a minted machine token (not a static API key) — with **zero core changes**\nand **no vendor specifics** (the gateway is entirely config/env).\n\nIt complements `#510` (env-var auth), which assumes a long-lived static key; this covers the\n\"mint-then-refresh a short-lived token\" case.\n\n## API surface (config / CLI / env)\n\nOpt-in only, via Headroom's existing flags — **no new CLI flags**:\n\n    headroom proxy --backend litellm-openai --proxy-extension oauth2\n    # or HEADROOM_PROXY_EXTENSIONS=oauth2\n\nAll configuration is env (12-factor; nothing baked in):\n\n| Env var | Required | Meaning |\n|---|---|---|\n| `HEADROOM_OAUTH2_TOKEN_URL` | yes (else no-op) | OAuth2 token endpoint; must be `https` (loopback `http` allowed for tests) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | yes | client credentials |\n| `HEADROOM_OAUTH2_SCOPES` | no | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | no | `audience` form param |\n| `HEADROOM_OAUTH2_RESOURCE` | no | RFC 8707 target `resource` form param |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | no | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | no | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | no | static upstream headers, `K=V,K2=V2` (control chars rejected) |\n| `HEADROOM_OAUTH2_TIMEOUT` / `_SKEW` | no | token request timeout / pre-expiry refresh skew (s) |\n| `HEADROOM_OAUTH2_ALLOW_INSECURE` | no | `1` to allow a non-loopback `http` token_url (discouraged) |\n\nPublic Python API: `OAuth2ClientCredentials`, `OAuth2Middleware`, `OAuth2Error`, `install`,\n`provider_from_env`, `parse_headers`.\n\n## Changes to existing behavior / defaults / compatibility\n\n- **None unless explicitly enabled.** The entry point is dormant until `--proxy-extension oauth2`\n  is passed, and even then a **no-op** unless `HEADROOM_OAUTH2_TOKEN_URL` is set.\n- When active, it **overwrites the request `Authorization` header** with the minted bearer before\n  the backend runs. The client's own `Authorization`/`x-api-key` is intentionally replaced (the\n  proxy authenticates to the gateway on the client's behalf). *Compatibility note:* because the\n  request then carries a bearer, Headroom classifies it as OAuth-mode auth — same as supplying a\n  bearer yourself; no new classification path.\n- No change to defaults, the request/response body, model routing, or compression.\n\n## User stories (Given / When / Then)\n\n- **Golden path** — *Given* a proxy started with `--proxy-extension oauth2` and valid\n  `TOKEN_URL`/`CLIENT_ID`/`CLIENT_SECRET`, *When* a client sends `/v1/messages`, *Then* the\n  extension mints (or reuses a cached) bearer and the upstream receives `Authorization: Bearer\n  <minted>` plus any static headers; the client never sees the secret.\n- **Edge: token endpoint down** — *Given* an unreachable/erroring `TOKEN_URL`, *When* a request\n  arrives, *Then* the proxy returns `502 upstream_auth_error` (no upstream call, no secret/body\n  leak) and stays up; the next request retries.\n- **Edge: wrong backend** — *Given* `--backend bedrock` (env-auth), *When* the extension installs,\n  *Then* it logs a loud warning that the injected bearer will have no effect and to use an\n  OpenAI-compatible/passthrough backend.\n\n## Failure modes & recovery\n\n| Failure | Behavior |\n|---|---|\n| Missing/invalid config at startup | `install()` raises -> proxy **fails closed** (won't start mis-auth'd) |\n| Token endpoint unreachable / non-2xx / non-JSON / no `access_token` | `OAuth2Error` -> `502`, per-request, proxy stays up, retried next request |\n| `expires_in` = 0/negative/absent | clamped to a positive TTL (never stale, never per-request mint) |\n| Concurrent first requests | single-flight lock -> exactly one mint per refresh |\n| Malformed `HEADROOM_OAUTH2_HEADERS` (CR/LF) | offending pair dropped with a warning (no header injection) |\n\n## Resilience (Docker / native / wrappers / providers / multi-process)\n\n- **Native & Docker:** identical; pure env-driven, std-lib only. Token minted via `urllib` against\n  the **system cert store**, so a corporate-injected CA is trusted with no bundled roots (works in\n  SSL-inspection networks).\n- **Wrappers (`headroom wrap`, agent hooks):** the extension lives at the proxy layer, so anything\n  routed through the proxy inherits it transparently.\n- **Providers:** effective for OpenAI-compatible / passthrough litellm backends (those that forward\n  the request bearer upstream). `bedrock`/`vertex`/`sagemaker` authenticate from env and ignore the\n  bearer -> the extension warns and is a no-op there.\n- **Multi-process (multiple workers):** the token cache is per-process; each worker mints/refreshes\n  independently. Acceptable for client-credentials (idempotent, low rate); no shared state, no\n  cross-process lock needed. Documented so operators can size token-endpoint rate limits.\n\n## Security & privacy\n\n- Secrets are env-only; **never logged** and **never returned** to the client.\n- The IdP error body is **drained, not surfaced** (may echo sensitive context).\n- `token_url` is **https-enforced** (loopback exception for tests; explicit opt-out env).\n- The minted bearer is sent only to the configured upstream; the client's inbound credential is\n  replaced, not forwarded onward.\n\n## Observability / logging / telemetry\n\n- `INFO` on install (token_url + auth style, no secrets) and on each mint (`ttl`, scopes).\n- `WARNING` on mint failure, env-auth-backend no-op, and dropped malformed static headers.\n- No metrics/telemetry emitted; piggybacks on Headroom's existing request logging. (A future\n  counter for mint/refresh/failure could be added if maintainers want it.)\n\n## Rollback / migration\n\n- **No migration** — additive and opt-in; existing deployments are unaffected.\n- **Instant rollback:** drop `--proxy-extension oauth2` (or unset `HEADROOM_PROXY_EXTENSIONS`), or\n  uninstall the package. No state to clean up, no config format changes.\n\n## Dependencies\n\n- **Runtime:** standard library only (no new core dependency). `litellm` is touched **only** if\n  `HEADROOM_OAUTH2_HEADERS` is set, and it is already a Headroom backend dependency — declared here\n  as the optional `[litellm]` extra, not a hard requirement.\n\n<!-- File: plugins/headroom-snip/hooks/hooks.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Hooks Skill\n\nPath: `plugins/headroom-snip/hooks/hooks.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/hooks/hooks.json)\n\n<!-- File: plugins/headroom-snip/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Headroom-snip Skill\n\nPath: `plugins/headroom-snip/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/tsconfig.json)\n\n<!-- File: plugins/hermes/headroom_retrieve/plugin.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Headroom_retrieve Skill\n\nPath: `plugins/hermes/headroom_retrieve/plugin.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/headroom_retrieve/plugin.yaml)\n\n<!-- File: plugins/openclaw/hook-shim/HOOK.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Hook-shim Skill\n\nPath: `plugins/openclaw/hook-shim/HOOK.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/hook-shim/HOOK.md)\n\n<!-- File: plugins/openclaw/package-lock.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Openclaw Skill\n\nPath: `plugins/openclaw/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package-lock.json)\n\n<!-- File: plugins/openclaw/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Openclaw Skill\n\nPath: `plugins/openclaw/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/package.json)\n\n<!-- File: plugins/openclaw/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Openclaw Skill\n\nPath: `plugins/openclaw/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/openclaw/tsconfig.json)\n\n<!-- File: plugins/opencode/package-lock.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Opencode Skill\n\nPath: `plugins/opencode/package-lock.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package-lock.json)\n\n<!-- File: plugins/opencode/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Opencode Skill\n\nPath: `plugins/opencode/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/package.json)\n\n<!-- File: plugins/opencode/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Opencode Skill\n\nPath: `plugins/opencode/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/opencode/tsconfig.json)\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~138 | Category: copilot-instructions) -->\nWhen performing a pull request review in this repository:\r\n\r\n1. Treat `.github/PULL_REQUEST_TEMPLATE.md` and `CONTRIBUTING.md` as required policy, not optional guidance.\r\n2. Flag pull requests that do not include concrete \"Real Behavior Proof\" with environment, exact commands or steps, observed result, and what was not tested.\r\n3. Be strict about contributor verification: missing tests, missing runtime evidence, or placeholder PR text should be called out.\r\n4. For user-facing, release, dependency, workflow, or security-sensitive changes, prefer blocking feedback over optional suggestions.\r\n5. Focus on correctness, safety, and whether the PR is actually ready for human maintainer review.\n\n<!-- File: .claude-plugin/marketplace.json (Tokens: ~386 | Category: marketplace) -->\n{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    },\n    {\n      \"name\": \"headroom-snip\",\n      \"source\": \"./plugins/headroom-snip\",\n      \"description\": \"Claude Code mod: watch Headroom snip tokens off every request, with an animated band, a /headroom log and a running total.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"claude-code\",\n        \"tokens\",\n        \"compression\",\n        \"mod\"\n      ]\n    }\n  ]\n}\n\n<!-- File: .github/plugin/marketplace.json (Tokens: ~218 | Category: marketplace) -->\n{\n  \"name\": \"headroom-marketplace\",\n  \"owner\": {\n    \"name\": \"Headroom Contributors\"\n  },\n  \"metadata\": {\n    \"description\": \"Headroom marketplace for Claude Code and GitHub Copilot CLI plugins.\",\n    \"version\": \"0.41.0\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"headroom\",\n      \"source\": \"./plugins/headroom-agent-hooks\",\n      \"description\": \"Headroom startup hooks for Claude Code and GitHub Copilot CLI.\",\n      \"version\": \"0.41.0\",\n      \"author\": {\n        \"name\": \"Headroom Contributors\",\n        \"url\": \"https://github.com/headroomlabs-ai/headroom\"\n      },\n      \"homepage\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"repository\": \"https://github.com/headroomlabs-ai/headroom\",\n      \"keywords\": [\n        \"headroom\",\n        \"hooks\",\n        \"claude-code\",\n        \"copilot-cli\"\n      ]\n    }\n  ]\n}\n\n<!-- File: e2e/wrap/tools/README.md (Tokens: ~300 | Category: plugin-manifest) -->\n# tools Documentation\n\nPath: `e2e/wrap/tools/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/e2e/wrap/tools/README.md)\n\n<!-- File: plugins/headroom-agent-hooks/.claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.claude-plugin/plugin.json)\n\n<!-- File: plugins/headroom-agent-hooks/.github/plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# plugin Plugin Manifest\n\nPath: `plugins/headroom-agent-hooks/.github/plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-agent-hooks/.github/plugin/plugin.json)\n\n<!-- File: plugins/headroom-agent-hooks/README.md (Tokens: ~292 | Category: plugin-manifest) -->\n# Headroom agent hooks\r\n\r\nThis plugin exposes lightweight startup hooks for Claude Code and GitHub Copilot CLI.\r\n\r\nThe hooks resolve and call:\n\r\n```bash\r\nheadroom init hook ensure\r\n```\r\n\r\nThat hidden helper checks for a matching durable `headroom init` deployment and starts it if needed.\n\nWhen `CLAUDE_PLUGIN_ROOT` points to a readable launcher, resolution order is\n`HEADROOM_BIN`, `headroom` on `PATH`, then `headroom` and\n`headroom.exe` in `$HOME/.local/bin`, `$HOME/.local/share/uv/tools/headroom-ai/bin`,\n`${PIPX_HOME:-$HOME/.local/pipx}/venvs/headroom-ai/bin`, `/opt/homebrew/bin`, and\n`/usr/local/bin`. If no executable is found, `HEADROOM_PYTHON`, `python3`, and\n`python` are checked for an importable `headroom` module and invoked as\n`python -m headroom.cli init hook ensure`.\n\nSet `HEADROOM_BIN` or `HEADROOM_PYTHON` to override discovery. An absent CLI emits\none actionable diagnostic and exits successfully, so the host hook remains\nnonblocking. Without a readable launcher, the hook runs bare\n`headroom init hook ensure` from `PATH` with none of the discovery above. Copilot\nCLI on Windows uses the manifest's `powershell` entry, which does the same.\n\n<!-- File: plugins/headroom-oauth2/README.md (Tokens: ~780 | Category: plugin-manifest) -->\n# headroom-oauth2\n\nGeneric **OAuth2 client-credentials** upstream-auth extension for the\n[Headroom](https://github.com/headroomlabs-ai/headroom) proxy.\n\nWhen Headroom routes to an OpenAI-compatible backend that is protected by an\nOAuth2 client-credentials flow (enterprise AI gateways, Azure AD / Entra, Okta,\nAuth0, Keycloak, Cognito, …), this extension mints a bearer token from a\nconfigurable token endpoint, caches + refreshes it (single-flight), and injects\n`Authorization: Bearer <token>` on each upstream request. Optional static upstream\nheaders are sent via litellm. **Fully vendor-neutral — no provider is hard-coded.**\n\nIt plugs into Headroom's public `headroom.proxy_extension` entry-point seam, so it\nis fully out-of-tree and opt-in.\n\n## Install & enable\n```bash\npip install headroom-oauth2\nheadroom proxy --backend litellm-openai --proxy-extension oauth2\n```\n\n## Configure (env; no-op unless HEADROOM_OAUTH2_TOKEN_URL is set)\n| Env | Meaning |\n|-----|---------|\n| `HEADROOM_OAUTH2_TOKEN_URL` | token endpoint (client_credentials grant) |\n| `HEADROOM_OAUTH2_CLIENT_ID` / `_CLIENT_SECRET` | credentials (secrets) |\n| `HEADROOM_OAUTH2_SCOPES` | space/comma-separated scopes |\n| `HEADROOM_OAUTH2_AUDIENCE` | optional audience |\n| `HEADROOM_OAUTH2_GRANT_TYPE` | default `client_credentials` |\n| `HEADROOM_OAUTH2_AUTH_STYLE` | `post` (form creds) or `basic` (HTTP Basic) |\n| `HEADROOM_OAUTH2_HEADERS` | static upstream headers, `K=V,K2=V2` |\n\nTokens are minted with the standard library (`urllib`, system cert store), which\nworks behind corporate SSL-inspection where bundled-root TLS stacks fail.\n\n\n**Effective backends:** the injected bearer reaches the upstream only for OpenAI-compatible /\npassthrough litellm providers. `bedrock` / `vertex` / `sagemaker` authenticate from env and\nignore it, so this extension is a no-op there (it logs a warning at startup).\n\n**Transport:** `token_url` must be `https` (loopback `http` is allowed for tests; set\n`HEADROOM_OAUTH2_ALLOW_INSECURE=1` to override). Tokens are minted with the standard library\n(`urllib`, system cert store), so a corporate-injected CA is trusted without bundling roots.\n\n## What gets the upstream bearer\n\nThe minted token is injected only on requests that **go upstream**. Routes the\nproxy answers itself — `/health`, `/livez`, `/readyz`, `/stats*`, `/metrics`,\n`/quota`, `/settings*`, `/dashboard*`, `/admin/*`, `/debug/*`, `/v1/compress*`,\n`/v1/usage`, `/v1/retrieve*`, `/v1/telemetry*`, `/v1/toin*`, `/v1/feedback*`,\nand any extension route under `/ext/` — are passed through untouched, so an\nunreachable IdP never turns a health probe into a 502 and management calls never\ncost a token mint. A `/p/<project>/` base-URL prefix is stripped before the\ncheck.\n\nRequires `headroom-ai` ≥ 0.40, where extension middleware runs inside the\nproxy's `HEADROOM_PROXY_TOKEN` gate: clients may then authenticate with\n`Authorization: Bearer <proxy token>` and the gate checks it before this\nextension replaces it with the upstream bearer.\n\n<!-- File: plugins/headroom-snip/.claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `plugins/headroom-snip/.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/headroom-snip/.claude-plugin/plugin.json)\n\n<!-- File: plugins/headroom-snip/README.md (Tokens: ~1087 | Category: plugin-manifest) -->\n# headroom-snip\n\nA Claude Code mod that shows what Headroom does to each request, live. When a\nrequest goes through the proxy, a pair of scissors runs along a bar the size of\nthe original prompt, cuts it down to what was actually sent, and the token\ncount drops as it goes:\n\n```\n✂ headroom 21k → 16k   tok ━━━━━━━━━━━━━━━━━━━━━━━✂⡀⠄⠂⠁⢀⠈⠐⠠ −81%\n✂ headroom 21k → 7.6k  tok ━━━━━━━━━━━✂⠈⠐⠠⡀⠄⠂⠁⢀⠈⠐⠠⡀⠄⠂······ −81%\n✂ headroom 21k → 4.1k  tok ━━━━━━·························· −81%\n  JSON crush ×2 · Kompress text · cache align   project 184k saved (62%) over 23 req ≈ 307 pages  details  hide\n```\n\n## What it shows\n\n- **The band above the prompt.** The latest request: original → sent tokens,\n  the snip animation, and the percentage cut. Below that, which compressors did\n  the cutting (`JSON crush`, `code AST`, `Kompress text`, `log squash`,\n  `cache align`, ...) and the running total since the session started. A request sent unchanged says why,\n  for example `kept: user message, recent code` or `nothing worth a snip`.\n- **`/headroom`.** Opens a pane with the requests since the session started: one bar per\n  request, what was cut and what was protected, how long compression took, the\n  biggest snip so far, and an all-time total.\n  `/headroom hide` and `/headroom show` toggle the band.\n- **The status line.** `✂ 184k tok saved · 62%`.\n- **Milestone toasts** at 10k, 50k, 100k, 250k, 500k, 1M and 5M tokens saved.\n- **No proxy?** If nothing answers, the band says so and suggests\n  `headroom wrap claude`.\n\n## How it works\n\nWhile a turn runs, the mod polls the proxy's loopback `GET /stats?cached=1`\nonce a second. It reads the `recent_requests` tail (per-request token counts\nand `transforms_applied`), and keeps polling for a few seconds after the turn\nends. Requests stamped before the session started count as history: they\naren't animated or added to the totals, even if the proxy only comes up later.\nNothing leaves your machine.\n\nThe proxy can't tell Claude Code sessions apart, so the totals are never\nper session. What they cover depends on how Claude Code reaches the proxy:\n\n- **Through `headroom wrap claude`:** each request carries an\n  `X-Headroom-Project` header naming the launch directory (its basename, so\n  two directories with the same name share a tag). The mod counts every\n  request with this session's tag, including other sessions in the same\n  project, and leaves other projects out. The proxy only reports tags for its\n  last ten requests, so a request it can't attribute is left out rather than\n  guessed. The band says \"project\" and `/headroom` names the project.\n- **Any other way:** there is no tag, so the totals cover every client on the\n  proxy since this session started. The band says \"proxy\" and `/headroom` says\n  so.\n\nIt finds the proxy in this order:\n\n1. `HEADROOM_PROXY_URL`\n2. `ANTHROPIC_BASE_URL` (as `headroom wrap claude` sets it)\n3. `http://127.0.0.1:8787`\n\nOnly loopback URLs are used: `http` or `https` on exactly `localhost`, `127.0.0.1`\nor `[::1]`, with no user or password. A value that isn't one (a remote proxy, or a\nhost like `localhost.example.com`) is skipped, so the mod never polls a remote host.\n\n## Install\n\n```bash\nclaude plugin marketplace add headroomlabs-ai/headroom\nclaude plugin install headroom-snip@headroom-marketplace\n```\n\nOr, from a checkout: `claude --plugin-dir plugins/headroom-snip`.\n\n## Develop\n\n```bash\nclaude plugin validate plugins/headroom-snip\nclaude plugin test plugins/headroom-snip      # tests/snip.test.tsx\ntsc -p plugins/headroom-snip                  # after Claude Code has loaded it once\n```\n\n`hooks/snip.ts` holds the pure parts (parsing, transform labels, the animation\nframes) and `hooks/register.tsx` holds the hooks and drawing.\n\n<!-- File: plugins/hermes/README.md (Tokens: ~300 | Category: plugin-manifest) -->\n# hermes Documentation\n\nPath: `plugins/hermes/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/headroomlabs-ai/headroom/HEAD/plugins/hermes/README.md)\n\n<!-- ... +3 more modular skills available via /api/skills/headroomlabs-ai/headroom?path={path} -->\n</yakaai_skills>"}