- headroom wrap claude is the simplest way to start up claude
- It will also install rtk-ai locally
- rtk-ai is a cli wrapper that can save ~90% tokens for CLI calls made by Claude Code
The model is a binary classifier — let it decide. When no target_ratio
is set (default proxy path), use argmax on token head logits directly
instead of score > 0.5 cutoff. Span head boosts borderline tokens
(0.3-0.5 probability) in important spans.
Result: compression adapts per content — 9% kept for verbose filler,
100% kept for dense commands/code. Previously uniform 29% everywhere.
Adds kompress_compressor.py — a self-contained ModernBERT-based token
compressor that auto-downloads from chopratejas/kompress-base on HuggingFace.
Trained on 330K structured tool outputs (JSON, diffs, logs, code, SQL,
agentic traces), achieving 82% entity preservation vs LLMLingua-2's 36%.
Changes:
- New: kompress_compressor.py — dual-head ModernBERT (token + span CNN)
with HuggingFace auto-download, no extra pip install needed
- ContentRouter: Kompress is primary ML compressor, LLMLingua-2 is fallback
- fallback_strategy changed from PASSTHROUGH to KOMPRESS — unknown/mixed
content now gets compressed instead of ignored
- No hardcoded compression ratios — model decides per-token importance,
optional target_ratio only when user explicitly sets it via API
- Version bump: 0.3.8 → 0.4.0
Dashboard was showing wildly incorrect metrics (99.5% savings, 3ms overhead)
due to using Anthropic API's non-cached input_tokens instead of optimized_tokens,
and dividing overhead by total request count instead of optimized-only count.
Key fixes:
- Use optimized_tokens (what we sent) for dashboard aggregation, not API's
input_tokens which excludes cached portion
- Track overhead_count separately from latency_count for correct averages
- Add TTFB (time to first byte) measurement, replace full stream latency in UI
- Eager-load LLMLingua model at proxy startup (eliminates 5.9s first-request delay)
- Simplify CostTracker to token-based accounting with counterfactual cost display
- Add two-tier compression cache to ContentRouter (skip set + result cache)
- Fix compression pinning to detect both CCR and ReadLifecycle markers
- Clamp tokens_saved to max(0, ...) across all provider paths
- Add per-transform timing instrumentation to pipeline
- Guard against over-aggressive code compression (<5% ratio)
- Fix ReadLifecycle partial read supersede logic (_read_covers range check)
- Disable CacheAligner and compress_superseded by default
- Fix all pre-existing mypy errors (CompressionCache return types)
- Fix test mocks to accept **kwargs for cache token parameters
SessionAnalyzer() without a model calls _detect_default_model() which
raises when no API keys are set (e.g., in CI). Pass model="test-model"
in the three tests that mock _call_llm.
Proxy performance logging (`headroom perf`):
- Add always-on RotatingFileHandler to ~/.headroom/logs/proxy.log (10MB x 5 backups)
- Replace scattered log lines with structured PERF lines containing model, msgs,
tok_before/after/saved, cache_read/write/hit_pct, opt_ms, and transforms
- Emit PERF lines from all three response paths (streaming Anthropic, non-streaming
Anthropic, Bedrock streaming)
- Add `headroom perf` CLI that parses proxy logs and reports token savings, cache
hit rates, prefix stability, transform effectiveness, routing breakdown, TOIN
status, and actionable recommendations
- Support --hours and --raw flags for time filtering and raw record output
Learn module rewrite (LLM-based analysis):
- Replace all regex/heuristic analyzers with a single LLM call via LiteLLM
- New SessionAnalyzer builds compact digests and sends to any of 100+ models
- Auto-detect best model from API keys (Anthropic → OpenAI → Gemini)
- Add --model flag for explicit model selection
- Enrich scanner with SessionEvent (user messages, interruptions, subagent summaries),
token usage tracking, and timestamps
- Simplify models: remove EnvironmentFact, StructureNote, Correction, CommandPattern,
RetryPattern, AnalysisReport; add SessionEvent, AnalysisResult
- Simplify writer: remove Recommender class (LLM now produces recommendations directly)
- Update tests for new analyzer and models
- Fix division-by-zero in OpenAI cache, BM25 scorer, BLEU metrics, and smart_crusher
- Add null safety for SQLite memory store JSON fields
- Add thread safety lock for CCR retrieval counter
- Add timeout/error handling for CCR stream collection
- Safer error logging and JSON serialization fallback in proxy server
- Return explicit zero stats on compression failure instead of None defaults
- Guard against missing "messages" key in ASGI and LiteLLM integrations
- Add aclose() for proper httpx client cleanup in ASGI middleware
- Expand DEFAULT_EXCLUDE_TOOLS to include Grep, Write, Edit
- Revert protect_recent_reads_fraction to 0.0 (protect all excluded-tool outputs)
- Fix whitespace waste detection to use tokenizer for both original and normalized
- Fix top-waste-requests sorting by tokens_saved instead of tokens_before
- Fix TOCTOU race in semantic cache _touch() method
- Fix mypy errors: type annotations for ASGI receive/send and proxy error logging
Address code review feedback on the initial MCP fix:
- mcp_uninstall: now also calls `claude mcp remove -s user` when the claude
CLI is available, mirroring mcp_install. Removes from mcp.json fallback
config as well if present. This fixes the broken uninstall->reinstall
roundtrip on machines using Claude Code CLI >=2.x.
- cli/mcp.py: move `import subprocess` to module level (was deferred inside
mcp_install function body, inconsistent with other stdlib imports and
harder to mock).
- tests: add TestMCPInstallWithClaudeCLI and TestMCPUninstallWithClaudeCLI
covering the previously-untested `claude mcp add` code path, including
force-overwrite ordering, -e flag for env vars, and fallback on failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes to get the headroom MCP server working with Claude Code CLI:
1. mcp_server.py: define CCR_TOOL_NAME inline instead of importing from
tool_injection, which triggered headroom/__init__.py -> LiteLLM -> HTTP
requests to GitHub, adding 4-5 seconds to startup time.
2. cli/mcp.py: prefer `claude mcp add -s user` when the claude CLI is
available (Claude Code CLI ≥2.x stores servers in ~/.claude/.claude.json,
not ~/.claude/mcp.json). Falls back to writing mcp.json for older versions
and the claude.ai desktop app.
3. tests/test_cli/test_mcp.py: update mock_claude_config_path fixture to
also stub out the claude CLI so install tests exercise the mcp.json
fallback path, matching the fixture's intent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable ReadLifecycle by default so stale/superseded Read outputs are
automatically replaced with compact CCR markers — these are provably safe
to compress (file was edited or re-read).
Replace static compression thresholds with adaptive parameters that scale
with conversation length and context pressure:
- protect_recent_reads_fraction: protects the most-recent 50% of messages
from Read exclusion. Old Reads beyond this window become compressible,
preventing the "28 excluded Read/Glob, 0 tokens saved" problem.
- min_ratio_relaxed / min_ratio_aggressive: compression acceptance
threshold interpolates linearly with context pressure (tokens / model
limit). Low pressure → 0.85 (picky), high pressure → 0.65 (accept
anything helpful). Eliminates the fixed 0.9 gate that was rejecting
20+ messages per request.
Also adds --no-read-lifecycle CLI flag, and fixes a missing
pytest.importorskip guard for sentence-transformers in memory tests.
CodeAwareCompressor now analyzes intra-file symbol relationships before
compression, using tree-sitter AST walks to count references, map call
graphs, and detect public/private visibility. This replaces uniform
"keep first N body lines" compression with budget-based allocation driven
by the existing target_compression_rate config.
Key design decisions:
- Distribution-based scoring (min-max normalized within each file) so it
adapts to any file structure: utility libs, test files, orchestrators
- Budget allocation: target_compression_rate determines total body line
budget, distributed proportionally to importance × body size
- max_body_lines respected as a hard cap over budget allocation
- Context-aware: the existing `context` parameter now boosts symbols
matching the user's task (word-boundary matching, not substring)
- Qualified names (ClassName.method) internally to avoid collisions
between identically-named methods in different classes
- Omitted comments include call graph info from AST analysis
- Zero new dependencies — uses tree-sitter already in headroom[code]
- semantic_analysis=True by default, fully backward-compatible when False
The AUTO vector backend prefers sqlite-vec over hnswlib. On GitHub
Actions runners, hnswlib's subprocess AVX probe fails (runner CPUs
lack AVX support), leaving no available vector backend and causing
test_memory_bridge.py to error with:
ValueError: hnswlib is not available. Install with: pip install hnswlib
sqlite-vec is a pure SQLite extension with pre-built wheels that works
on all CI runners without requiring AVX. Adding it to [dev] lets the
AUTO backend select it instead of falling through to the failing HNSW path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Docker example in proxy.md used the wrong package name and lacked
build-essential, causing install failures on slim images. hnswlib (a
core dependency) requires a C++ compiler to build from source.
- Fix proxy.md Docker example: headroom[proxy] -> headroom-ai[proxy],
add build-essential install/cleanup pattern
- Add troubleshooting entry for C++ compilation errors with solutions
for Linux and macOS environments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hnswlib may be used by core features at runtime even without the
[memory] extra explicitly installed. Safer to leave it in core deps
and document the C++ build requirement instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
hnswlib requires C++ compilation and is only used by the memory
subsystem - it belongs in the [memory] extra, not core dependencies.
Installing headroom-ai on slim Docker images or any environment
without build tools would fail at the hnswlib build step.
Also fixes docs/quickstart.md and docs/troubleshooting.md which
referenced the wrong PyPI package name `headroom` (an unrelated
package) instead of `headroom-ai`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Codex adapter: CodexScanner reads ~/.codex/sessions/*.json, CodexWriter
writes to AGENTS.md + instructions.md. Tested on 328 real sessions.
- Gemini writer: GeminiWriter writes to GEMINI.md (scanner deferred,
sessions stored in protobuf).
- CLI --agent flag: auto-detect available agents or specify claude/codex/gemini.
- Quality gates: min_evidence, min_confidence, min_total_evidence thresholds
prevent weak signals from writing noise to project files.
- Integration tests against real Claude Code and Codex session data on disk.
Tests skip gracefully if data directories don't exist.
- Bash path extraction for Codex (reads files via sed/cat, not Read tool).
- Idempotency, false positive filtering, and skip-write-on-empty tests.
Analyzes past conversation history to find tool call failure patterns,
correlates each failure with what eventually succeeded, and writes
specific project-level learnings to CLAUDE.md and MEMORY.md.
Key design:
- Success correlation: extracts the diff between failed and successful
inputs as the learning (not generic advice)
- Generic architecture: tool-agnostic ToolCall model with pluggable
Scanner/Writer adapters (Claude Code first, extensible to Cursor/Codex)
- 5 analyzers: Environment, Structure, Commands, Retries, Cross-Session
- Dry-run by default, --apply to write, --all for all projects
Also fixes mypy errors in litellm_callback, asgi, langchain chat_model,
and anthropic provider (AsyncClient typing, ToolCall arg-type, int cast).
Both CompressionMiddleware and HeadroomCallback now support a cloud mode
(api_key="hdr_xxx") that calls Headroom Cloud API for managed compression
with org-scoped CCR, TOIN learning, and analytics. Falls back to
HEADROOM_API_KEY env var. Local mode (default) is unchanged.
Also adds x-headroom-tokens-before/after response headers and updates
uv.lock with mcp extra and version bump to 0.3.3.
LangChain provides tool_call args in different shapes (dict args, str
arguments, nested function.arguments) depending on the source. Add
_tool_call_args_to_json() helper to normalize all formats to JSON strings.
Use .get() instead of [] to handle missing keys gracefully.
Detects Read tool outputs that became stale (file was later edited) or
superseded (file was later re-Read) and replaces them with compact markers
+ CCR hashes. Fresh Reads are never touched.
Adds ReadLifecycleConfig to config.py and integrates ReadLifecycleManager
as a pre-processing pass in ContentRouter. Opt-in via config flag to
preserve backward-compatible behavior.
Foundational models (Claude Code, ChatGPT) store memory in flat .md files while
Headroom uses a semantic vector store. This bridge connects the two worlds —
importing .md files into Headroom for semantic search, exporting Headroom memories
back to .md, and keeping them in sync with hash-based change detection.
Three new integration paths — no proxy needed:
1. headroom.compress(messages, model) → CompressResult
One function, auto-detects tokenizer per model, works with any client.
2. headroom.integrations.asgi.CompressionMiddleware
Drop-in ASGI middleware for LiteLLM proxy, FastAPI, or any ASGI app.
3. headroom.integrations.litellm_callback.HeadroomCallback
LiteLLM callback: litellm.callbacks = [HeadroomCallback()]
Fix: TransformPipeline._get_tokenizer() no longer requires a Provider.
Falls back to tokenizer registry which auto-detects per model:
- OpenAI → tiktoken (exact)
- Anthropic → calibrated estimation (3.5 chars/token)
- Open models → HuggingFace (if installed)
15 tests covering compress(), ASGI middleware, LiteLLM callback.
Query Echo addresses attention decay in compressed contexts. After
SmartCrusher compresses tool outputs, the user's question may be
thousands of tokens away. Echo appends a brief reminder after the
last compressed block.
- New: headroom/transforms/query_echo.py
- Compression-ratio-proportional: only triggers when >30% compressed
- Cache-safe: appended at end (after KV cache boundary)
- Provider-agnostic: Anthropic, OpenAI, Gemini
- 18 tests (15 unit + 3 integration with real API)
- Fix _crush_array 4-tuple unpack in test_critical_fixes.py