headroom/README.md

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

476 lines
29 KiB
Markdown
Raw Normal View History

2026-06-04 15:14:36 -07:00
<div align="center"><pre>
██╗ ██╗███████╗ █████╗ ██████╗ ██████╗ ██████╗ ██████╗ ███╗ ███╗
██║ ██║██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔═══██╗██╔═══██╗████╗ ████║
███████║█████╗ ███████║██║ ██║██████╔╝██║ ██║██║ ██║██╔████╔██║
██╔══██║██╔══╝ ██╔══██║██║ ██║██╔══██╗██║ ██║██║ ██║██║╚██╔╝██║
██║ ██║███████╗██║ ██║██████╔╝██║ ██║╚██████╔╝╚██████╔╝██║ ╚═╝ ██║
╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝
2026-07-06 09:07:54 -07:00
The context compression layer for AI agents
2026-06-04 15:14:36 -07:00
</pre></div>
<p align="center"><strong>6095% fewer tokens (for JSON data), 15-20% fewer tokens (for coding agents) · library · proxy · MCP · content-aware compressors · local-first · reversible</strong></p>
<p align="center">
<a href="https://github.com/chopratejas/headroom/actions/workflows/ci.yml"><img src="https://github.com/chopratejas/headroom/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
<a href="https://app.codecov.io/gh/chopratejas/headroom"><img src="https://codecov.io/gh/chopratejas/headroom/graph/badge.svg" alt="codecov"></a>
<a href="https://pypi.org/project/headroom-ai/"><img src="https://img.shields.io/pypi/v/headroom-ai.svg" alt="PyPI"></a>
<a href="https://www.npmjs.com/package/headroom-ai"><img src="https://img.shields.io/npm/v/headroom-ai.svg" alt="npm"></a>
feat: switch Kompress default to kompress-v2-base with weight-only int8 ONNX (#799) ## Summary Replaces `chopratejas/kompress-base` with **`chopratejas/kompress-v2-base`** as the default Kompress text-compression model (the fallback for content not handled by structured compressors), using a new **weight-only int8 ONNX** artifact that is fp32-equivalent at 2.2x less memory. ## Why v2 is the same dual-head ModernBERT (token classifier + span CNN), LoRA-trained on the v2 dataset. The HF repo originally shipped PyTorch weights only — pointing Headroom at it naively would have forced the heavy `[ml]` (torch) path on every `[proxy]` install. We exported ONNX artifacts reproducing the v1 loader contract (single `final_scores` output) and published them to the HF repo. ## Eval (labeled dataset_v2 test split, n=500, threshold 0.5) | artifact | size | f1 | must_keep_recall | keep_rate | fp32 agreement | |---|---|---|---|---|---| | fp32 (reference) | 601 MB | 0.9128 | 0.9770 | 0.8100 | 100% | | **int8-wo (default)** | **261 MB** | **0.9130** | **0.9765** | **0.8097** | **99.6%** | | fp16 | 301 MB | 0.9129 | 0.9771 | 0.8099 | 99.9% | | int4-wo | 230 MB | 0.9102 | 0.9825 | 0.8354 ⚠️ | 94.5% | | int8-dynamic | 271 MB | 0.9041 | 0.9868 | 0.8857 ⚠️ | 90.5% | Weight-only int8 (MatMulNBits) keeps activations fp32, avoiding the upward score bias that makes dynamic int8 keep ~7% more tokens (≈40% less compression savings). Quantized candidates were generated and eval-gated by a Modal job in the kompress repo (`modal_jobs/export_onnx_v2.py`) against the labeled test split. ## Changes - Default model id → `chopratejas/kompress-v2-base` - ONNX artifact resolution tries candidates in order (**int8-wo → fp32 → v1 int8**), falling through on download miss **or session-load failure** — onnxruntime builds without the MatMulNBits 8-bit kernel fall back to fp32 instead of losing Kompress - `HEADROOM_KOMPRESS_ONNX_FILENAME` env pins an exact artifact - `scripts/export_kompress_v2_onnx.py`: reproducible fp32 export (loads the merged v2 checkpoint, traces the `final_scores` contract, verifies vs PyTorch) - `.gitignore`: local `onnx/` artifacts dir; allowlist the export script ## Testing - End-to-end: fresh `KompressCompressor().preload()` resolves int8-wo from HF, loads on onnxruntime 1.23 (CPU, no torch), compresses with error/traceback content preserved - fp32 export verified lossless vs PyTorch (max |Δscore| = 0.0, 100% keep agreement) - ruff check + format clean, mypy clean, 63 targeted tests pass
2026-06-09 22:28:40 -08:00
<a href="https://huggingface.co/chopratejas/kompress-v2-base"><img src="https://img.shields.io/badge/model-Kompress--v2--base-yellow.svg" alt="Model: Kompress-v2-base"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License: Apache 2.0"></a>
<a href="https://headroom-docs.vercel.app/docs"><img src="https://img.shields.io/badge/docs-online-blue.svg" alt="Docs"></a>
</p>
<p align="center">
<a href="https://headroom-docs.vercel.app/docs">Docs</a> ·
<a href="#get-started-60-seconds">Install</a> ·
<a href="#proof">Proof</a> ·
<a href="#agent-compatibility-matrix">Agents</a> ·
docs: improve discoverability for AI agents and search crawlers Several signals AI agents and search engines use to discover and install a project were misaligned or missing: * ``docs/app/layout.tsx`` set ``metadataBase`` to ``https://chopratejas.github.io/headroom/`` while the live docs run on Vercel — every page's ``og:url`` and ``twitter:url`` resolved to a URL that returns 404 for ``/llms.txt``. Now points at the live Vercel host (overridable via ``NEXT_PUBLIC_SITE_URL`` for a future custom domain). Adds explicit ``openGraph`` and ``twitter`` metadata so social shares render a card with the project's pitch. * No ``llms.txt`` at the GitHub repo root. AI agents crawling ``github.com/chopratejas/headroom/`` saw only the README. The new ``llms.txt`` follows the llmstxt.org convention: 1-line pitch, canonical docs links, copy-paste install commands (pip / npm / Docker / proxy / ``headroom wrap``), and entry points for the library, proxy, MCP server, and SDK integrations. Points at the Fumadocs-generated ``/llms.txt`` and ``/llms-full.txt`` for the full picture. * ``pyproject.toml`` ``Documentation`` URL pointed at the GitHub README anchor. Updated to point at the docs site so PyPI visitors land on searchable docs, and adds an ``AI / LLM Index`` URL pointing at the Fumadocs ``/llms.txt``. * No explicit AI-bot allow list. Added ``docs/app/robots.ts`` (Next 13+ App Router convention) with explicit allows for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, OAI-SearchBot, ChatGPT-User, Cohere-AI, CCBot, and Applebot-Extended. Wildcard allow as the catch-all. Advertises the sitemap. * No ``sitemap.xml`` route. Added ``docs/app/sitemap.ts`` that pulls every Fumadocs page out of ``source`` (same source backing ``/llms.txt``, search, and OG images) so search and AI crawlers can enumerate doc pages without scraping HTML. * README didn't tell AI agents where to look. Added a 2-line pointer near the top nav row: read ``/llms.txt`` here, or fetch the live index / full docs blob. Also tightened the GitHub repo description and added five topics (``claude-code``, ``cursor``, ``tokens``, ``prompt-engineering``, ``typescript``) via ``gh repo edit`` — that's already live on the repo, not part of this commit. No Python or Rust code changes; ``make ci-precheck`` was run to confirm the test slice still passes.
2026-05-13 17:36:06 -07:00
<a href="https://discord.gg/yRmaUNpsPJ">Discord</a> ·
chore: remove committed node_modules + stray/internal markdown (repo hygiene) (#1528) ## Description Repo hygiene for a public OSS project: removes committed `node_modules`, stray/internal/draft markdown, and commercial-surface references — keeping every real doc (the published docs site, the wiki guides, and all component READMEs) intact. Every file was content-audited before removal, and load-bearing files were verified against the code/CI and kept. Net: **1,695 files changed, +23 / −266,409** (the deletions are dominated by a committed `node_modules` tree). Closes # (no tracking issue) ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [x] Code refactoring (no functional changes) ## Changes Made **Removed (verified to have no code/CI dependencies):** - `examples/vercel-ai-sdk-pr/` — 1,649 committed `node_modules` files (zero example source); `node_modules/` added to `.gitignore`. - `docs/spec/` (23 draft "Living Specification" files — orphaned, `1.0.0-draft`, drifted from the code), `docs/superpowers/` (2 agent plans), `docs/proposals/` (2 internal/commercial memos). - 6 orphan `docs/*.md` (auth-modes, bedrock, claude-code-vertex-headroom, cortex-code, output-token-reduction-guide, rtk-loop-weighting). - `PR.md` (committed PR draft), `ENTERPRISE.md`, `.github/FUNDING.yml`. **Content scrubs:** - Removed unreleased "Headroom Cloud" / `api.headroom.ai` / `hr_` references from `configuration.mdx`, `wiki/configuration.md`, `wiki/typescript-sdk.md`, `sdk/typescript/README.md` (reworded to neutral, accurate phrasing). - Dropped a stale "awaiting maintainer before merge" line from `plugins/headroom-oauth2/SPEC.md`; tidied `.gitignore` comments (kept the protective `headroom-managed/` ignore rule). - Fixed the now-dangling links into removed files (README nav/`output-token-reduction` link, `scripts/README`, `wiki/vertex`). **Explicitly KEPT (load-bearing — would orphan in-code citations if removed):** - `.changelog.md` — consumed by `.github/workflows/release.yml` (read as the release-notes file). - `REALIGNMENT/`, `docs/observability.md`, `docs/rtk-architecture.md`, `wiki/plans/`, `TESTING-copilot-subscription.md` — referenced by the Rust core / Python / tests as design docs. ## Testing - [ ] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [ ] Type checking passes (`mypy`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text # Docs/markdown + .gitignore only — no Python/Rust source changed, so the # behavioral test suite is unaffected. Verified the cleanup did not orphan # references or break the published docs site: $ git ls-files 'docs/content/docs/*.mdx' | wc -l # published site intact 42 $ # meta.json nav unchanged; no published page removed. $ grep -rnI "Headroom Cloud|api.headroom.ai|'hr_" $(git ls-files '*.md' '*.mdx') >>> none $ # dangling refs to removed files (excl pre-existing P0/P2 spec stubs that $ # never existed in git): none remaining. ``` ## Real Behavior Proof - Environment: macOS, local git clone of the repo (markdown/.gitignore changes only — no runtime). - Exact command / steps: 4 read-only content-audit agents classified every `.md`/`.mdx` file; each removal candidate was cross-checked against the codebase (`grep` for citations in `.rs`/`.py`/tests, workflows, and configs); only files with no dependents were removed; the tree was re-grepped after removal to confirm no new dangling references; verified the published docs site page count (`git ls-files 'docs/content/docs/*.mdx' | wc -l` = 42, unchanged). - Observed result: the 42-page published docs site and all wiki guides are untouched; no source or workflow references a removed file; `.changelog.md` (consumed by release.yml) and the code-cited design docs were detected as dependencies and kept; the committed `node_modules` tree is removed and `node_modules/` is gitignored so it can't be re-committed; zero "Headroom Cloud"/`headroom.dev` references remain. - Not tested: N/A — no executable code changed (only markdown, `.mdx`, and `.gitignore`), so the behavioral test suite is unaffected. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - This branch deletes `.github/FUNDING.yml` while PR #1526 edits it — the two will be sequenced at merge (delete wins). - A follow-up option (not in this PR): also remove the internal design docs that are currently cited by the code (`REALIGNMENT/`, `docs/observability.md`, `docs/rtk-architecture.md`, `wiki/plans/`) — that requires scrubbing ~15–20 in-code citations so nothing dangles, so it's deliberately deferred. - Untracked local working files (`benchmarks/hf_pilot/`, `tools/copilot-test/`) are intentionally left out of git (not committed).
2026-06-27 23:32:54 -07:00
<a href="llms.txt">llms.txt</a>
</p>
docs: improve discoverability for AI agents and search crawlers Several signals AI agents and search engines use to discover and install a project were misaligned or missing: * ``docs/app/layout.tsx`` set ``metadataBase`` to ``https://chopratejas.github.io/headroom/`` while the live docs run on Vercel — every page's ``og:url`` and ``twitter:url`` resolved to a URL that returns 404 for ``/llms.txt``. Now points at the live Vercel host (overridable via ``NEXT_PUBLIC_SITE_URL`` for a future custom domain). Adds explicit ``openGraph`` and ``twitter`` metadata so social shares render a card with the project's pitch. * No ``llms.txt`` at the GitHub repo root. AI agents crawling ``github.com/chopratejas/headroom/`` saw only the README. The new ``llms.txt`` follows the llmstxt.org convention: 1-line pitch, canonical docs links, copy-paste install commands (pip / npm / Docker / proxy / ``headroom wrap``), and entry points for the library, proxy, MCP server, and SDK integrations. Points at the Fumadocs-generated ``/llms.txt`` and ``/llms-full.txt`` for the full picture. * ``pyproject.toml`` ``Documentation`` URL pointed at the GitHub README anchor. Updated to point at the docs site so PyPI visitors land on searchable docs, and adds an ``AI / LLM Index`` URL pointing at the Fumadocs ``/llms.txt``. * No explicit AI-bot allow list. Added ``docs/app/robots.ts`` (Next 13+ App Router convention) with explicit allows for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, OAI-SearchBot, ChatGPT-User, Cohere-AI, CCBot, and Applebot-Extended. Wildcard allow as the catch-all. Advertises the sitemap. * No ``sitemap.xml`` route. Added ``docs/app/sitemap.ts`` that pulls every Fumadocs page out of ``source`` (same source backing ``/llms.txt``, search, and OG images) so search and AI crawlers can enumerate doc pages without scraping HTML. * README didn't tell AI agents where to look. Added a 2-line pointer near the top nav row: read ``/llms.txt`` here, or fetch the live index / full docs blob. Also tightened the GitHub repo description and added five topics (``claude-code``, ``cursor``, ``tokens``, ``prompt-engineering``, ``typescript``) via ``gh repo edit`` — that's already live on the repo, not part of this commit. No Python or Rust code changes; ``make ci-precheck`` was run to confirm the test slice still passes.
2026-05-13 17:36:06 -07:00
<p align="center"><sub>
<b>AI agents / LLMs:</b> read <a href="llms.txt"><code>/llms.txt</code></a> here, or fetch <a href="https://headroom-docs.vercel.app/llms.txt">the live index</a> / <a href="https://headroom-docs.vercel.app/llms-full.txt">full docs blob</a>.
</sub></p>
---
2026-06-04 15:14:36 -07:00
<p align="center"><a href="https://trendshift.io/repositories/20881" target="_blank"><img src="https://trendshift.io/api/badge/repositories/20881" alt="chopratejas%2Fheadroom | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a></p>
2026-06-04 15:14:36 -07:00
Headroom compresses everything your AI agent reads — tool outputs, logs, RAG chunks, files, and conversation history — before it reaches the LLM. Same answers, fraction of the tokens.
<p align="center">
<img src="HeadroomDemo-Fast.gif" alt="Headroom in action" width="820">
<br/><sub>Live: 10,144 → 1,260 tokens — same FATAL found.</sub>
</p>
## What it does
- **Library** — `compress(messages)` in Python or TypeScript, inline in any app
- **Proxy** — `headroom proxy --port 8787`, zero code changes, any language
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
- **Agent wrap** — `headroom wrap claude|codex|copilot|cursor|aider|opencode|cline|continue|goose|openhands|openclaw|vibe` in one command; undo with `headroom unwrap <tool>`
- **MCP server** — `headroom_compress`, `headroom_retrieve`, `headroom_stats` for any MCP client
- **Cross-agent memory** — shared store across Claude, Codex, Gemini, auto-dedup
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
- **`headroom learn`** — mines failed sessions, writes corrections to `CLAUDE.local.md` (default, gitignored) or `CLAUDE.md` / `AGENTS.md` / `GEMINI.md`
feat: output-token reduction — verbosity shaper, per-user learning, counterfactual savings (#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
2026-06-16 21:06:43 -07:00
- **Output token reduction** — trims what the model *writes back* (not just what you send): drops ceremony/restated code and skips deep "thinking" on routine steps. See [Output token reduction](#output-token-reduction-cut-what-the-model-writes-back).
fix(ccr): make retrieval TTL configurable (#715) ## Description Make the CCR retrieval store TTL configurable so long-running agent jobs can keep `headroom_retrieve` markers resolvable beyond the previous hard-coded 300-second window. Fixes #714 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Add `HEADROOM_CCR_TTL_SECONDS` for the global CCR `CompressionStore` default TTL, with validation and fallback to 300 seconds. - Expose the effective CCR TTL as `store.default_ttl_seconds` from `/v1/retrieve/stats`. - Distinguish missing vs expired CCR retrieval failures in `/v1/retrieve`, `/v1/retrieve/{hash}`, tool-call handling, and CCR response handling. - Update CCR docs, README wording, and CHANGELOG for the user-facing TTL behavior. - Add regression tests for env-configured TTL, invalid env fallback, explicit TTL precedence, stats exposure, and expired retrieval detail. ## Reproduction Before this change, the proxy-global CCR store always used the default 300-second TTL when callers used `get_compression_store()` without an explicit `default_ttl`. A long-running agent job could receive a `<<ccr:...>>` marker and fail later with a generic not-found/expired response after the fixed 5-minute retention window. The new tests cover this by setting `HEADROOM_CCR_TTL_SECONDS`, creating CCR entries through the same global store used by the proxy, and asserting that stored entries and `/v1/retrieve/stats` use the configured retention. ## Real behavior proof Setup tested: - macOS 15.7.2 - Python 3.13.9 via `uv run --frozen --extra dev --extra proxy` - Local Headroom proxy subprocess: `python -m headroom.proxy.server` - Proxy config: `HEADROOM_TELEMETRY=off`, `HEADROOM_CACHE_ENABLED=false`, `HEADROOM_RATE_LIMIT_ENABLED=false` - Provider/model: no live upstream provider needed; exercised local `/v1/compress` -> `/v1/retrieve` CCR HTTP flow with model `gpt-4o` Exact steps run after the patch: 1. Start a real Headroom proxy process with `HEADROOM_CCR_TTL_SECONDS=7200`. 2. POST a 200-item tool-result payload to `/v1/compress`. 3. Extract the emitted `<<ccr:...>>` marker hash from the compressed messages. 4. GET `/v1/retrieve/stats`. 5. POST `/v1/retrieve` with the marker hash. 6. Repeat with `HEADROOM_CCR_TTL_SECONDS=1`, wait 1.5 seconds, and retrieve the same way to verify explicit expiration reporting. Observed result: ```json { "long_ttl": { "ccr_hash": "b473e632aa47", "retrieve_status": 200, "retrieved_content_has_result_199": true, "stats_default_ttl_seconds": 7200, "stats_entry_count": 1, "ttl_seconds": 7200 }, "short_ttl_expired": { "ccr_hash": "b473e632aa47", "retrieve_detail": "Entry expired (CCR TTL: 1 seconds; age: 2 seconds)", "retrieve_status": 404, "stats_default_ttl_seconds": 1, "stats_entry_count": 1, "ttl_seconds": 1 } } ``` What I did not test: - A live OpenRouter/OpenAI/Anthropic upstream request. - A durable/non-memory CCR backend. - A literal 5+ minute wall-clock wait; the process E2E used `7200` to prove configured retention and `1` second to prove expiration behavior quickly. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ## Test Output ```bash UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_compression_store.py tests/test_proxy_ccr.py tests/test_ccr_response_handler.py tests/test_ccr_response_handler_extra.py # 152 passed, 2 warnings in 12.87s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_adapter_hooks.py tests/test_toin_feedback.py tests/test_toin_fixes.py # 55 passed, 13 skipped, 1 warning in 0.53s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff check . # All checks passed! UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff format --check . # 776 files already formatted UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy mypy headroom # Success: no issues found in 346 source files ``` Existing warnings observed in the targeted tests were unrelated to this change: - AnthropicProvider tiktoken approximation warning in proxy CCR tests. - Deprecated `ToolIntelligenceNetwork.get_recommendation()` warning in existing TOIN assertions. ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) Not applicable. ## Additional Notes No new dependencies. Default behavior remains 300 seconds unless `HEADROOM_CCR_TTL_SECONDS` is set.
2026-06-11 13:20:46 +09:00
- **Reversible (CCR)** — originals are cached for retrieval on demand
## How it works (30 seconds)
```
Your agent / app
(Claude Code, Cursor, Codex, LangChain, Agno, Strands, your own code…)
│ prompts · tool outputs · logs · RAG results · files
┌────────────────────────────────────────────────────┐
│ Headroom (runs locally — your data stays here) │
│ ──────────────────────────────────────────────── │
│ CacheAligner → ContentRouter → CCR │
│ ├─ SmartCrusher (JSON) │
│ ├─ CodeCompressor (AST) │
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
│ └─ Kompress-v2-base (text, HF) │
│ │
│ Cross-agent memory · headroom learn · MCP │
└────────────────────────────────────────────────────┘
│ compressed prompt + retrieval tool
LLM provider (Anthropic · OpenAI · Bedrock · …)
```
- **ContentRouter** — detects content type, selects the right compressor
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
- **SmartCrusher / CodeCompressor / Kompress-v2-base** — compress JSON, AST, or prose
- **CacheAligner** — stabilizes prefixes so provider KV caches actually hit
- **CCR** — stores originals locally; LLM calls `headroom_retrieve` if it needs them
feat: switch Kompress default to kompress-v2-base with weight-only int8 ONNX (#799) ## Summary Replaces `chopratejas/kompress-base` with **`chopratejas/kompress-v2-base`** as the default Kompress text-compression model (the fallback for content not handled by structured compressors), using a new **weight-only int8 ONNX** artifact that is fp32-equivalent at 2.2x less memory. ## Why v2 is the same dual-head ModernBERT (token classifier + span CNN), LoRA-trained on the v2 dataset. The HF repo originally shipped PyTorch weights only — pointing Headroom at it naively would have forced the heavy `[ml]` (torch) path on every `[proxy]` install. We exported ONNX artifacts reproducing the v1 loader contract (single `final_scores` output) and published them to the HF repo. ## Eval (labeled dataset_v2 test split, n=500, threshold 0.5) | artifact | size | f1 | must_keep_recall | keep_rate | fp32 agreement | |---|---|---|---|---|---| | fp32 (reference) | 601 MB | 0.9128 | 0.9770 | 0.8100 | 100% | | **int8-wo (default)** | **261 MB** | **0.9130** | **0.9765** | **0.8097** | **99.6%** | | fp16 | 301 MB | 0.9129 | 0.9771 | 0.8099 | 99.9% | | int4-wo | 230 MB | 0.9102 | 0.9825 | 0.8354 ⚠️ | 94.5% | | int8-dynamic | 271 MB | 0.9041 | 0.9868 | 0.8857 ⚠️ | 90.5% | Weight-only int8 (MatMulNBits) keeps activations fp32, avoiding the upward score bias that makes dynamic int8 keep ~7% more tokens (≈40% less compression savings). Quantized candidates were generated and eval-gated by a Modal job in the kompress repo (`modal_jobs/export_onnx_v2.py`) against the labeled test split. ## Changes - Default model id → `chopratejas/kompress-v2-base` - ONNX artifact resolution tries candidates in order (**int8-wo → fp32 → v1 int8**), falling through on download miss **or session-load failure** — onnxruntime builds without the MatMulNBits 8-bit kernel fall back to fp32 instead of losing Kompress - `HEADROOM_KOMPRESS_ONNX_FILENAME` env pins an exact artifact - `scripts/export_kompress_v2_onnx.py`: reproducible fp32 export (loads the merged v2 checkpoint, traces the `final_scores` contract, verifies vs PyTorch) - `.gitignore`: local `onnx/` artifacts dir; allowlist the export script ## Testing - End-to-end: fresh `KompressCompressor().preload()` resolves int8-wo from HF, loads on onnxruntime 1.23 (CPU, no torch), compresses with error/traceback content preserved - fp32 export verified lossless vs PyTorch (max |Δscore| = 0.0, 100% keep agreement) - ruff check + format clean, mypy clean, 63 targeted tests pass
2026-06-09 22:28:40 -08:00
→ [Architecture](https://headroom-docs.vercel.app/docs/architecture) · [CCR reversible compression](https://headroom-docs.vercel.app/docs/ccr) · [Kompress-v2-base model card](https://huggingface.co/chopratejas/kompress-v2-base)
## Get started (60 seconds)
```bash
# 1 — Install
docs: clarify the headroom CLI is pip-only; npm headroom-ai is the TS SDK (#1585) ## Description `npm install headroom-ai` doesn't give you the `headroom` CLI — it's the TypeScript SDK (a library, no `bin`). The README's "Get started" and "Install" blocks listed the npm install next to the pip install and then immediately ran `headroom wrap claude`, so Node/Windows users reasonably expected npm to provide the CLI and hit `'headroom' is not recognized`. This spells out the split: CLI = pip, SDK = npm. The hnswlib/MSVC half of the report was already fixed on main in #1499 (moved hnswlib to the optional `[vector]` extra), so this PR only addresses the npm-CLI confusion. Closes #1470 ## Type of Change - [x] Documentation update ## Changes Made - README "Get started" + "Install" blocks: annotate that pip ships the `headroom` CLI and npm `headroom-ai` is the TS SDK with no CLI; note the `headroom` commands come from the pip install. - `docs/content/docs/installation.mdx`: state the TS SDK does not install the `headroom` CLI. ## Testing - [x] Manual testing performed ### Test Output ```text Docs-only change. Verified against the source of truth: - pyproject.toml: [project.scripts] headroom = "headroom.cli:main" (CLI entry point is Python-only) - sdk/typescript/package.json: name "headroom-ai", no "bin" field (SDK, no CLI) ``` ## Real Behavior Proof - Environment: repo main @ HEAD - Exact command / steps: read `[project.scripts]` in pyproject.toml and the `bin` field in sdk/typescript/package.json - Observed result: `headroom` console script is defined only by the Python package; the npm package has no `bin`, so `npm install headroom-ai` provides no `headroom` command — matching the issue. - Not tested: n/a (no code paths changed) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings
2026-06-30 21:17:47 +05:30
pip install "headroom-ai[all]" # Python — ships the `headroom` CLI
npm install headroom-ai # TypeScript SDK only — no `headroom` CLI
docs: clarify the headroom CLI is pip-only; npm headroom-ai is the TS SDK (#1585) ## Description `npm install headroom-ai` doesn't give you the `headroom` CLI — it's the TypeScript SDK (a library, no `bin`). The README's "Get started" and "Install" blocks listed the npm install next to the pip install and then immediately ran `headroom wrap claude`, so Node/Windows users reasonably expected npm to provide the CLI and hit `'headroom' is not recognized`. This spells out the split: CLI = pip, SDK = npm. The hnswlib/MSVC half of the report was already fixed on main in #1499 (moved hnswlib to the optional `[vector]` extra), so this PR only addresses the npm-CLI confusion. Closes #1470 ## Type of Change - [x] Documentation update ## Changes Made - README "Get started" + "Install" blocks: annotate that pip ships the `headroom` CLI and npm `headroom-ai` is the TS SDK with no CLI; note the `headroom` commands come from the pip install. - `docs/content/docs/installation.mdx`: state the TS SDK does not install the `headroom` CLI. ## Testing - [x] Manual testing performed ### Test Output ```text Docs-only change. Verified against the source of truth: - pyproject.toml: [project.scripts] headroom = "headroom.cli:main" (CLI entry point is Python-only) - sdk/typescript/package.json: name "headroom-ai", no "bin" field (SDK, no CLI) ``` ## Real Behavior Proof - Environment: repo main @ HEAD - Exact command / steps: read `[project.scripts]` in pyproject.toml and the `bin` field in sdk/typescript/package.json - Observed result: `headroom` console script is defined only by the Python package; the npm package has no `bin`, so `npm install headroom-ai` provides no `headroom` command — matching the issue. - Not tested: n/a (no code paths changed) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings
2026-06-30 21:17:47 +05:30
# 2 — Pick your mode (the `headroom` commands below come from the pip install)
headroom wrap claude # wrap a coding agent
headroom proxy --port 8787 # drop-in proxy, zero code changes
# or: from headroom import compress # inline library
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
# 3 — Verify setup and see the savings
headroom doctor # health check — confirms routing is working
2026-06-03 23:51:40 +09:00
headroom perf
feat(cli): add `headroom dashboard` and surface the dashboard URL (#1277) (#1292) ## Description The savings dashboard is served at `GET /dashboard` (`headroom/proxy/server.py`) but was effectively undiscoverable: there was no `headroom dashboard` command, the `wrap` startup banner only printed `Proxy ready on http://127.0.0.1:PORT` (never the dashboard URL), and the docs buried it — so users on current releases didn't know it existed (#1277). This makes it discoverable from the CLI, the wrap banner, and the docs. Closes #1277 ## Type of Change - [x] New feature (non-breaking change that adds functionality) ## Changes Made - `headroom/cli/proxy.py`: new `headroom dashboard` command — prints `http://127.0.0.1:<port>/dashboard` and opens it in a browser (stdlib `webbrowser`); `--no-open` just prints, `--port`/`HEADROOM_PORT` honored. Headless failures are swallowed (URL already printed). - `headroom/cli/wrap.py`: print the dashboard URL alongside "Proxy ready" so every `wrap` surfaces it. - `docs/content/docs/installation.mdx` + `README.md`: document `headroom dashboard`. - `docs/content/docs/mcp.mdx`: document the Codex MCP `command: "headroom"` PATH pitfall (#768) — a project-venv (`uv add`) install isn't on the host's PATH; install globally with `uv tool install` / pipx, or use an absolute path. - `tests/test_cli_dashboard.py`: new tests. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [x] New tests added for new functionality ### Test Output ```text $ python -m pytest tests/test_cli_dashboard.py -q 3 passed $ python -m ruff check headroom/cli/proxy.py headroom/cli/wrap.py tests/test_cli_dashboard.py All checks passed! ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.13, branch fix/1277-dashboard-discoverability off headroomlabs-ai/main - Exact command / steps: built the CLI and invoked the new command via the real entry-point import (`from headroom.cli.main import main; main(['dashboard','--no-open','--port','8787'], standalone_mode=False)`) and checked it is registered (`'dashboard' in main.commands`). - Observed result: prints ` Dashboard: http://127.0.0.1:8787/dashboard`, `'dashboard' in main.commands` → `True`, exit 0. The three new tests pass (prints URL + no browser on `--no-open`; opens the URL by default; a raising `webbrowser.open` does not crash the command). - Not tested: did not load the rendered `/dashboard` HTML against a live proxy in CI — the change only adds a launcher/printer for the existing route; the route itself is unchanged. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 02:05:38 +02:00
headroom dashboard # live savings dashboard (proxy must be running)
```
docs: clarify the headroom CLI is pip-only; npm headroom-ai is the TS SDK (#1585) ## Description `npm install headroom-ai` doesn't give you the `headroom` CLI — it's the TypeScript SDK (a library, no `bin`). The README's "Get started" and "Install" blocks listed the npm install next to the pip install and then immediately ran `headroom wrap claude`, so Node/Windows users reasonably expected npm to provide the CLI and hit `'headroom' is not recognized`. This spells out the split: CLI = pip, SDK = npm. The hnswlib/MSVC half of the report was already fixed on main in #1499 (moved hnswlib to the optional `[vector]` extra), so this PR only addresses the npm-CLI confusion. Closes #1470 ## Type of Change - [x] Documentation update ## Changes Made - README "Get started" + "Install" blocks: annotate that pip ships the `headroom` CLI and npm `headroom-ai` is the TS SDK with no CLI; note the `headroom` commands come from the pip install. - `docs/content/docs/installation.mdx`: state the TS SDK does not install the `headroom` CLI. ## Testing - [x] Manual testing performed ### Test Output ```text Docs-only change. Verified against the source of truth: - pyproject.toml: [project.scripts] headroom = "headroom.cli:main" (CLI entry point is Python-only) - sdk/typescript/package.json: name "headroom-ai", no "bin" field (SDK, no CLI) ``` ## Real Behavior Proof - Environment: repo main @ HEAD - Exact command / steps: read `[project.scripts]` in pyproject.toml and the `bin` field in sdk/typescript/package.json - Observed result: `headroom` console script is defined only by the Python package; the npm package has no `bin`, so `npm install headroom-ai` provides no `headroom` command — matching the issue. - Not tested: n/a (no code paths changed) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings
2026-06-30 21:17:47 +05:30
The `headroom` CLI ships **only** via the PyPI package. The npm `headroom-ai` is the TypeScript SDK — a library you import (`import { compress } from 'headroom-ai'`), not a CLI, so it provides no `headroom` command.
fix(packaging): move hnswlib to optional [vector] extra so [all] needs no C++ toolchain (#1499) ## Description `pip install "headroom-ai[all]"` aborts on any machine without a C++ toolchain. `[all]` pulls `[memory]`, which was the only extra carrying `hnswlib>=0.8.0`. hnswlib compiles from source where no wheel matches the target, and that build failure rolls back the **entire** `[all]` install. hnswlib is already fully optional at runtime: `MemoryConfig` defaults to `VectorBackend.AUTO` → **sqlite-vec** (pure Python, no compiler), and only falls back to HNSW. So `[memory]` does not need hnswlib to function. This moves hnswlib into a dedicated optional `[vector]` extra, exactly like `[pytorch-mps]` is already kept out of `[all]`. Closes #1368 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `pyproject.toml`: - Removed `hnswlib>=0.8.0` from `[memory]` (keeps `sqlite-vec` + `sentence-transformers`; the default sqlite-vec backend still works). - Added `vector = ["hnswlib>=0.8.0"]` for users who opt into the HNSW backend. - `[all]` still references `[memory]` (now hnswlib-free) and does **not** add `[vector]`, so it resolves with no compiler. - `[dev]` keeps `hnswlib`, so CI still installs and exercises the HNSW backend tests. - Docs: documented the new `[vector]` extra in `installation.mdx` and the README, and noted it is excluded from `[all]`; fixed the `[memory]` row that claimed to bundle hnswlib. No application code changed. ## Testing - [x] Linting passes (`ruff check .`) - [x] Manual testing performed (TOML resolution check — see proof) - [ ] Unit tests pass (`pytest`) — no app code changed; existing memory/HNSW tests are unaffected (the HNSW backend dependency moved extras but `[dev]`/CI still install it). ### Test Output ```text $ python - <<'PY' # resolve [all] transitively and check hnswlib placement memory has hnswlib: False vector has hnswlib: True dev has hnswlib: True [all] resolved has hnswlib: False [all] has sqlite-vec: True [all] has sentence-transformers: True PY $ ruff check headroom/ tests/ All checks passed! ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.13.11; `tomllib` + a small transitive-extra resolver over the edited `pyproject.toml`. - Exact command / steps: parse `pyproject.toml`, expand `headroom-ai[...]` self-references in `[all]` recursively, then check which extras carry `hnswlib`. - Observed result: the resolved `[all]` set contains no hnswlib while `[vector]` and `[dev]` do. Full output: ```text memory has hnswlib: False vector has hnswlib: True dev has hnswlib: True [all] resolved has hnswlib: False [all] has sqlite-vec: True [all] has sentence-transformers: True ``` `[all]` now resolves with **no** hnswlib (so no compiler needed), while the HNSW backend stays installable via `[vector]` and still tested via `[dev]`. - Not tested: a real `pip install` on a compiler-less host (the failure is a build-time rollback that the resolver check captures deterministically); the native-wrapper e2e jobs that this `pyproject.toml` change triggers run `wrap` e2e, not the memory HNSW path, so dropping hnswlib from `[all]` does not affect them. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Additional Notes - Editing `pyproject.toml` trips the `e2e` path filter, so the Windows/macOS/Docker native-wrapper jobs also run on this PR. They install + run the `wrap` e2e flow (not the memory HNSW backend), so the extras change is safe for them. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 22:16:55 +02:00
Granular extras: `[proxy]`, `[mcp]`, `[ml]`, `[code]`, `[memory]`, `[vector]` (optional HNSW backend — needs a C++ toolchain, not in `[all]`), `[relevance]`, `[image]`, `[agno]`, `[langchain]`, `[evals]`, `[pytorch-mps]` (Apple-GPU memory-embedder offload — set `HEADROOM_EMBEDDER_RUNTIME=pytorch_mps`). Requires **Python 3.10+**.
## Proof
**Savings on real agent workloads:**
| Workload | Before | After | Savings |
|-------------------------------|-------:|-------:|--------:|
| Code search (100 results) | 17,765 | 1,408 | **92%** |
| SRE incident debugging | 65,694 | 5,118 | **92%** |
| GitHub issue triage | 54,174 | 14,761 | **73%** |
| Codebase exploration | 78,502 | 41,254 | **47%** |
**Accuracy preserved on standard benchmarks:**
| Benchmark | Category | N | Baseline | Headroom | Delta |
|------------|----------|----:|---------:|---------:|------------|
| GSM8K | Math | 100 | 0.870 | 0.870 | **±0.000** |
| TruthfulQA | Factual | 100 | 0.530 | 0.560 | **+0.030** |
| SQuAD v2 | QA | 100 | — | **97%** | 19% compression |
| BFCL | Tools | 100 | — | **97%** | 32% compression |
Reproduce: `python -m headroom.evals suite --tier 1` · [Full benchmarks & methodology](https://headroom-docs.vercel.app/docs/benchmarks)
feat: output-token reduction — verbosity shaper, per-user learning, counterfactual savings (#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
2026-06-16 21:06:43 -07:00
## Output token reduction (cut what the model writes back)
Everything above shrinks the prompt you **send**. But you also pay for every
token the model **writes back** — and on Opus-class models output costs 5× input.
A lot of that output is waste: "Great, let me…" preambles, re-printing code you
just showed it, and deep "thinking" on routine steps like reading a file.
Headroom can trim that too, from the proxy, without you changing any code:
- **Verbosity steering** — appends a short "be terse, don't restate context"
note to the end of the system prompt (so your prompt cache still hits).
- **Effort routing** — when a turn is just the model resuming after a tool result
(a file read, a passing test), it dials the model's thinking effort down. New
questions and errors keep full effort.
Turn it on:
```bash
export HEADROOM_OUTPUT_SHAPER=1 # off by default
headroom proxy --port 8787
```
feat(proxy): hot-reload live env knobs so a reused proxy picks them up without a restart (#1090) ## Description A small class of env vars is read by the proxy **live, per request** — the output-shaper family (`HEADROOM_OUTPUT_SHAPER`, `HEADROOM_VERBOSITY_LEVEL`, `HEADROOM_EFFORT_ROUTER`, `HEADROOM_MECHANICAL_EFFORT`, `HEADROOM_VERBOSITY_AUTOTUNE`, `HEADROOM_OUTPUT_HOLDOUT`), or captured at import (`HEADROOM_INTERCEPT_READ_MIN_CHARS`). The proxy reads them from its own process environment, fixed at launch. But `headroom wrap` reuses an already-running proxy (it restarts only on startup-config drift), so a value exported *after* the proxy started silently no-op'd — e.g. `export HEADROOM_OUTPUT_SHAPER=1` had zero effect on a reused proxy on `:8787`. This PR makes those live knobs **hot-reloadable**: `headroom wrap` pushes them to the running proxy, which applies them in memory — no restart (a restart would cold-start the ML stack, drop in-flight requests, and lose CCR/router caches). _No linked issue._ ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `headroom/proxy/runtime_env.py` (new): single source of truth registering the live knobs + a thread-safe process-global override store. `getenv()` (override-then-env) is a drop-in for `os.environ.get`; behaviour is byte-identical when no override is set. - Readers rerouted through `runtime_env.getenv`: `output_shaper.py`, the anthropic holdout read, and the ast-grep threshold (now a live read, not an import-time constant). - Proxy: loopback-only `POST /admin/runtime-env` applies overrides in memory; `/health` → `config.runtime_env` surfaces the live values so reuse is observable. - `wrap`: after attaching to a proxy (all call sites), best-effort push of the session's **explicitly-set** knobs. No-ops if nothing is set, `--no-proxy`, the proxy is unreachable, or it predates the endpoint (404). Only explicitly-set knobs are pushed, so a session never clobbers another with a default it never asked for. - Docs: README + output-token-reduction guide document the global-override caveat. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text $ python -m pytest tests/test_runtime_env.py -q 16 passed $ python -m pytest tests/test_runtime_env.py tests/test_output_shaper.py -q 50 passed $ ruff check headroom/proxy/runtime_env.py headroom/proxy/output_shaper.py headroom/proxy/handlers/anthropic.py headroom/proxy/interceptors/astgrep.py headroom/proxy/server.py headroom/cli/wrap.py All checks passed! $ mypy headroom/proxy/runtime_env.py Success: no issues found in 1 source file ``` ## Real Behavior Proof - Environment: local macOS, Python 3.12 `.venv`, branch `fix/runtime-env-hot-reload` at the PR head. - Exact command / steps: ran the test suites above. The 16 new `test_runtime_env` tests exercise the registry/store, overrides reaching the shaper + the ast-grep threshold, the `POST /admin/runtime-env` apply + `/health` reflect + loopback-only 404 + 400-on-non-object, and the wrap push payload / no-op / error-swallow paths. - Observed result: 50 passed; ruff + mypy clean on the changed modules; an override set via the endpoint is read by `getenv()` at the shaper and surfaced in `/health` config. - Not tested: a literal two-terminal manual session (start a proxy, `headroom wrap` a second session, `export HEADROOM_OUTPUT_SHAPER=1`, confirm the reused proxy picks it up). The behaviour is covered by the endpoint + wrap-push integration tests, but was not exercised by hand here. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - **Inherent caveat (documented):** overrides are global to the proxy — one process serves every attached wrapper, so the last explicit setting wins. No mechanism (restart or hot-reload) can give two sessions on one shared proxy different output-shaper settings. - **Scope:** startup-captured settings (`HEADROOM_TARGET_RATIO` etc.) are intentionally out of scope — a fresh proxy already gets them and they ride the existing `/health` config channel. - **Merge blocker:** this branch is currently **CONFLICTING with `main`** and needs a rebase/merge before it can land. - CHANGELOG.md left unchanged — releases are managed by release-please from conventional commits.
2026-06-18 09:50:50 -07:00
> **Already running a proxy?** These switches are read *live* on every request,
> so a proxy that `headroom wrap` **reused** (rather than started) would not see
> a value you export afterwards — its environment was snapshotted at launch.
> `headroom wrap` now hot-syncs your current settings to the running proxy via a
> loopback `POST /admin/runtime-env`, so they take effect immediately with **no
> restart** (no cold start, no dropped requests, no lost caches). Set them before
> you `wrap`. On a shared proxy these overrides are global — the last explicit
> setting wins.
feat: output-token reduction — verbosity shaper, per-user learning, counterfactual savings (#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
2026-06-16 21:06:43 -07:00
**Learn the right terseness for you.** People don't *say* how terse they want
answers — they *show* it (they interrupt long replies, or move on before they
could have read them). `headroom learn --verbosity` reads your past sessions and
picks the level automatically:
```bash
headroom learn --verbosity # preview what it found (dry run)
headroom learn --verbosity --apply # save it; the proxy uses it from now on
```
**See how many output tokens you saved.** Output savings are *counterfactual*
we never see what the model *would* have written — so Headroom reports an honest
**estimate with a confidence range**, never a made-up number:
```bash
headroom output-savings
# Reduction: 31.7% (95% CI 27.7% … 35.7%) [estimated]
```
Want a *measured* number instead of an estimate? Leave 10% of conversations
unshaped as a control group: `export HEADROOM_OUTPUT_HOLDOUT=0.1`. The dashboard
shows an **Output Tokens Saved** card next to input compression, labelled
`measured` or `estimated` with the confidence band.
chore: remove committed node_modules + stray/internal markdown (repo hygiene) (#1528) ## Description Repo hygiene for a public OSS project: removes committed `node_modules`, stray/internal/draft markdown, and commercial-surface references — keeping every real doc (the published docs site, the wiki guides, and all component READMEs) intact. Every file was content-audited before removal, and load-bearing files were verified against the code/CI and kept. Net: **1,695 files changed, +23 / −266,409** (the deletions are dominated by a committed `node_modules` tree). Closes # (no tracking issue) ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [x] Code refactoring (no functional changes) ## Changes Made **Removed (verified to have no code/CI dependencies):** - `examples/vercel-ai-sdk-pr/` — 1,649 committed `node_modules` files (zero example source); `node_modules/` added to `.gitignore`. - `docs/spec/` (23 draft "Living Specification" files — orphaned, `1.0.0-draft`, drifted from the code), `docs/superpowers/` (2 agent plans), `docs/proposals/` (2 internal/commercial memos). - 6 orphan `docs/*.md` (auth-modes, bedrock, claude-code-vertex-headroom, cortex-code, output-token-reduction-guide, rtk-loop-weighting). - `PR.md` (committed PR draft), `ENTERPRISE.md`, `.github/FUNDING.yml`. **Content scrubs:** - Removed unreleased "Headroom Cloud" / `api.headroom.ai` / `hr_` references from `configuration.mdx`, `wiki/configuration.md`, `wiki/typescript-sdk.md`, `sdk/typescript/README.md` (reworded to neutral, accurate phrasing). - Dropped a stale "awaiting maintainer before merge" line from `plugins/headroom-oauth2/SPEC.md`; tidied `.gitignore` comments (kept the protective `headroom-managed/` ignore rule). - Fixed the now-dangling links into removed files (README nav/`output-token-reduction` link, `scripts/README`, `wiki/vertex`). **Explicitly KEPT (load-bearing — would orphan in-code citations if removed):** - `.changelog.md` — consumed by `.github/workflows/release.yml` (read as the release-notes file). - `REALIGNMENT/`, `docs/observability.md`, `docs/rtk-architecture.md`, `wiki/plans/`, `TESTING-copilot-subscription.md` — referenced by the Rust core / Python / tests as design docs. ## Testing - [ ] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [ ] Type checking passes (`mypy`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text # Docs/markdown + .gitignore only — no Python/Rust source changed, so the # behavioral test suite is unaffected. Verified the cleanup did not orphan # references or break the published docs site: $ git ls-files 'docs/content/docs/*.mdx' | wc -l # published site intact 42 $ # meta.json nav unchanged; no published page removed. $ grep -rnI "Headroom Cloud|api.headroom.ai|'hr_" $(git ls-files '*.md' '*.mdx') >>> none $ # dangling refs to removed files (excl pre-existing P0/P2 spec stubs that $ # never existed in git): none remaining. ``` ## Real Behavior Proof - Environment: macOS, local git clone of the repo (markdown/.gitignore changes only — no runtime). - Exact command / steps: 4 read-only content-audit agents classified every `.md`/`.mdx` file; each removal candidate was cross-checked against the codebase (`grep` for citations in `.rs`/`.py`/tests, workflows, and configs); only files with no dependents were removed; the tree was re-grepped after removal to confirm no new dangling references; verified the published docs site page count (`git ls-files 'docs/content/docs/*.mdx' | wc -l` = 42, unchanged). - Observed result: the 42-page published docs site and all wiki guides are untouched; no source or workflow references a removed file; `.changelog.md` (consumed by release.yml) and the code-cited design docs were detected as dependencies and kept; the committed `node_modules` tree is removed and `node_modules/` is gitignored so it can't be re-committed; zero "Headroom Cloud"/`headroom.dev` references remain. - Not tested: N/A — no executable code changed (only markdown, `.mdx`, and `.gitignore`), so the behavioral test suite is unaffected. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - This branch deletes `.github/FUNDING.yml` while PR #1526 edits it — the two will be sequenced at merge (delete wins). - A follow-up option (not in this PR): also remove the internal design docs that are currently cited by the code (`REALIGNMENT/`, `docs/observability.md`, `docs/rtk-architecture.md`, `wiki/plans/`) — that requires scrubbing ~15–20 in-code citations so nothing dangles, so it's deliberately deferred. - Untracked local working files (`benchmarks/hf_pilot/`, `tools/copilot-test/`) are intentionally left out of git (not committed).
2026-06-27 23:32:54 -07:00
→ Full write-up incl. the measurement methodology: [Output token reduction](https://headroom-docs.vercel.app/docs/savings)
feat: output-token reduction — verbosity shaper, per-user learning, counterfactual savings (#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
2026-06-16 21:06:43 -07:00
2026-06-05 16:49:46 -07:00
<a href="https://www.star-history.com/?repos=chopratejas%2Fheadroom&type=date&legend=top-left">
<picture>
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=chopratejas/headroom&type=date&legend=top-left" />
</picture>
</a>
## Agent compatibility matrix
feat(providers): add Cortex Code (Snowflake CoCo) as a supported agent (#1190) ## Description Adds **Cortex Code (CoCo)** — Snowflake's AI coding CLI — as a first-class headroom provider alongside Claude Code, Codex, and Cursor. Cortex Code routes requests to Snowflake's Cortex inference endpoint via the OpenAI-compatible pipeline. This PR adds the provider slice, registers it under `"cortex-code"`, and ships tests that measure real token savings against `claude-sonnet-4-6`. Closes # ## Type of Change - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - `headroom/providers/cortex_code/__init__.py` — new provider package - `headroom/providers/cortex_code/runtime.py` — `proxy_base_url()`, `build_launch_env()`, `default_api_url()` (reads `SNOWFLAKE_HOST` / `SNOWFLAKE_ACCOUNT`) - `headroom/providers/cortex_code/install.py` — `build_install_env()` sets `OPENAI_BASE_URL`; `render_setup_lines()` - `headroom/providers/install_registry.py` — registers `"cortex-code"` in `_ENV_BUILDERS` - `tests/test_provider_cortex_code.py` — 15 unit tests - `tests/test_cortex_code_compression.py` — 5 compression benchmark tests (no API key needed) - `tests/e2e_cortex_savings.py` — real REST API benchmark; reads `SF_CONN`/`SF_HOST` from env, no hardcoded identifiers - `docs/cortex-code.md` — integration guide (quick start, library mode, auth, limitations) - `README.md` — Cortex Code row added to agent compatibility matrix ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run --with pytest pytest tests/test_provider_cortex_code.py tests/test_cortex_code_compression.py -v tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_is_openai_compatible PASSED tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_uses_given_port PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_install_env_sets_openai_base_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_does_not_mutate_input PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_applies_project_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_ignores_blank_project PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_contains_proxy_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_project_attribution PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_reads_snowflake_host_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_constructs_url_from_account_name PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_host_takes_priority_over_account PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_falls_back_when_no_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_preserves_https_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_includes_cortex_code PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_unknown_target_skipped PASSED tests/test_cortex_code_compression.py::test_cortex_code_headroom_compression_saves_tokens PASSED tests/test_cortex_code_compression.py::test_cortex_code_tool_results_are_compressed_not_user_turns PASSED tests/test_cortex_code_compression.py::test_cortex_code_tables_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_rag_search_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_compression_is_lossless_on_key_content PASSED 20 passed, 1 warning in 1.91s ``` ## Real Behavior Proof - Environment: macOS, Python 3.11, headroom 0.27.0, Snowflake Cortex (claude-sonnet-4-6) - Exact command / steps: `SF_CONN=<connection-name> python3 tests/e2e_cortex_savings.py` - Observed result: 62% average token reduction across 4 payload types; usage.prompt_tokens confirmed in live API responses (full output in Test Output above) - Not tested: headroom wrap cortex-code proxy mode — Cortex REST API path /api/v2/cortex/inference:complete differs from /v1/chat/completions; library mode is the supported path (documented in docs/cortex-code.md Limitations) ```text Tokens saved : 22,077 prompt tokens (4 calls) Avg per call : 5,519 tokens / $0.01656 At 1k/day : $16.56/day | $6,044/year ``` ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Pre-commit hooks skipped locally due to a GPG signing / ruff-format stash conflict in the dev environment. `ruff check` passes clean on all new files. --------- Co-authored-by: Cortex Code <noreply@snowflake.com>
2026-06-21 22:18:47 -07:00
| Agent | `headroom wrap` | Notes |
|--------------|:---------------:|----------------------------------|
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
| Claude Code | ✅ | `--memory` · `--code-graph` · `--1m` · `--tool-search` |
feat(providers): add Cortex Code (Snowflake CoCo) as a supported agent (#1190) ## Description Adds **Cortex Code (CoCo)** — Snowflake's AI coding CLI — as a first-class headroom provider alongside Claude Code, Codex, and Cursor. Cortex Code routes requests to Snowflake's Cortex inference endpoint via the OpenAI-compatible pipeline. This PR adds the provider slice, registers it under `"cortex-code"`, and ships tests that measure real token savings against `claude-sonnet-4-6`. Closes # ## Type of Change - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - `headroom/providers/cortex_code/__init__.py` — new provider package - `headroom/providers/cortex_code/runtime.py` — `proxy_base_url()`, `build_launch_env()`, `default_api_url()` (reads `SNOWFLAKE_HOST` / `SNOWFLAKE_ACCOUNT`) - `headroom/providers/cortex_code/install.py` — `build_install_env()` sets `OPENAI_BASE_URL`; `render_setup_lines()` - `headroom/providers/install_registry.py` — registers `"cortex-code"` in `_ENV_BUILDERS` - `tests/test_provider_cortex_code.py` — 15 unit tests - `tests/test_cortex_code_compression.py` — 5 compression benchmark tests (no API key needed) - `tests/e2e_cortex_savings.py` — real REST API benchmark; reads `SF_CONN`/`SF_HOST` from env, no hardcoded identifiers - `docs/cortex-code.md` — integration guide (quick start, library mode, auth, limitations) - `README.md` — Cortex Code row added to agent compatibility matrix ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run --with pytest pytest tests/test_provider_cortex_code.py tests/test_cortex_code_compression.py -v tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_is_openai_compatible PASSED tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_uses_given_port PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_install_env_sets_openai_base_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_does_not_mutate_input PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_applies_project_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_ignores_blank_project PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_contains_proxy_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_project_attribution PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_reads_snowflake_host_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_constructs_url_from_account_name PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_host_takes_priority_over_account PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_falls_back_when_no_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_preserves_https_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_includes_cortex_code PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_unknown_target_skipped PASSED tests/test_cortex_code_compression.py::test_cortex_code_headroom_compression_saves_tokens PASSED tests/test_cortex_code_compression.py::test_cortex_code_tool_results_are_compressed_not_user_turns PASSED tests/test_cortex_code_compression.py::test_cortex_code_tables_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_rag_search_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_compression_is_lossless_on_key_content PASSED 20 passed, 1 warning in 1.91s ``` ## Real Behavior Proof - Environment: macOS, Python 3.11, headroom 0.27.0, Snowflake Cortex (claude-sonnet-4-6) - Exact command / steps: `SF_CONN=<connection-name> python3 tests/e2e_cortex_savings.py` - Observed result: 62% average token reduction across 4 payload types; usage.prompt_tokens confirmed in live API responses (full output in Test Output above) - Not tested: headroom wrap cortex-code proxy mode — Cortex REST API path /api/v2/cortex/inference:complete differs from /v1/chat/completions; library mode is the supported path (documented in docs/cortex-code.md Limitations) ```text Tokens saved : 22,077 prompt tokens (4 calls) Avg per call : 5,519 tokens / $0.01656 At 1k/day : $16.56/day | $6,044/year ``` ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Pre-commit hooks skipped locally due to a GPG signing / ruff-format stash conflict in the dev environment. `ruff check` passes clean on all new files. --------- Co-authored-by: Cortex Code <noreply@snowflake.com>
2026-06-21 22:18:47 -07:00
| Codex | ✅ | shares memory with Claude |
docs: clarify Cursor setup support (#1439) ## Description Clarifies Cursor support so the docs no longer imply Cursor is fully auto-configured or launched like CLI agents. `headroom wrap cursor` starts the local proxy and prints base URLs for Cursor settings; Cursor still requires manual settings changes in the app. Closes #1436 ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Updated the README feature list so Cursor is not grouped with one-command launch/configure agents. - Changed the README compatibility matrix to mark Cursor as manual setup and explain what `headroom wrap cursor` actually does. - Updated proxy docs to say Cursor reads endpoints from its settings UI and to remove the misleading `OPENAI_BASE_URL=... cursor` example. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run --with pytest --with pytest-asyncio python -m pytest tests/test_provider_cursor.py tests/test_cli/test_wrap_bridge.py::test_wrap_cursor_prepare_only_injects_cursorrules tests/test_cli/test_wrap_bridge.py::test_wrap_cursor_prepare_only_uses_lean_ctx_when_configured -q 7 passed in 0.65s cd docs && npm run types:check fumadocs-mdx && next typegen && tsc --noEmit Types generated successfully cd docs && npm run build next build Compiled successfully; generated static pages successfully. Note: existing Recharts width/height warnings were emitted during static generation. uv run --with mkdocs-material mkdocs build Documentation built in 1.52 seconds. Note: existing mkdocs nav/link warnings were emitted. git diff --check (no output) ``` ## Real Behavior Proof - Environment: Windows PowerShell, Python 3.13.3, Node/npm from local environment, isolated worktree `C:\git\headroom\.worktrees\issue-1368-install-prereqs`. - Exact command / steps: inspected `headroom.providers.cursor.runtime.render_setup_lines`, Cursor provider tests, and `headroom wrap cursor --prepare-only` coverage; ran the commands listed above. - Observed result: Cursor runtime only renders manual setup instructions and project-attributed base URLs; docs now match that behavior. Local Cursor-focused tests and docs builds passed. - Not tested: launching the Cursor desktop app or manually configuring Cursor settings, because this PR changes documentation only. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A - documentation wording only. ## Additional Notes Tests were not added because the implementation behavior was already covered; this PR aligns the public docs with the existing Cursor runtime behavior. Ruff and mypy were not run because no Python code changed. CHANGELOG is not updated for this docs-only clarification.
2026-06-25 13:40:02 -05:00
| Cursor | Manual setup | starts proxy and prints base URLs for Cursor settings |
feat(providers): add Cortex Code (Snowflake CoCo) as a supported agent (#1190) ## Description Adds **Cortex Code (CoCo)** — Snowflake's AI coding CLI — as a first-class headroom provider alongside Claude Code, Codex, and Cursor. Cortex Code routes requests to Snowflake's Cortex inference endpoint via the OpenAI-compatible pipeline. This PR adds the provider slice, registers it under `"cortex-code"`, and ships tests that measure real token savings against `claude-sonnet-4-6`. Closes # ## Type of Change - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - `headroom/providers/cortex_code/__init__.py` — new provider package - `headroom/providers/cortex_code/runtime.py` — `proxy_base_url()`, `build_launch_env()`, `default_api_url()` (reads `SNOWFLAKE_HOST` / `SNOWFLAKE_ACCOUNT`) - `headroom/providers/cortex_code/install.py` — `build_install_env()` sets `OPENAI_BASE_URL`; `render_setup_lines()` - `headroom/providers/install_registry.py` — registers `"cortex-code"` in `_ENV_BUILDERS` - `tests/test_provider_cortex_code.py` — 15 unit tests - `tests/test_cortex_code_compression.py` — 5 compression benchmark tests (no API key needed) - `tests/e2e_cortex_savings.py` — real REST API benchmark; reads `SF_CONN`/`SF_HOST` from env, no hardcoded identifiers - `docs/cortex-code.md` — integration guide (quick start, library mode, auth, limitations) - `README.md` — Cortex Code row added to agent compatibility matrix ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run --with pytest pytest tests/test_provider_cortex_code.py tests/test_cortex_code_compression.py -v tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_is_openai_compatible PASSED tests/test_provider_cortex_code.py::test_cortex_code_proxy_base_url_uses_given_port PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_install_env_sets_openai_base_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_does_not_mutate_input PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_applies_project_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_build_launch_env_ignores_blank_project PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_contains_proxy_url PASSED tests/test_provider_cortex_code.py::test_cortex_code_render_setup_lines_project_attribution PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_reads_snowflake_host_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_constructs_url_from_account_name PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_host_takes_priority_over_account PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_falls_back_when_no_env PASSED tests/test_provider_cortex_code.py::test_cortex_code_default_api_url_preserves_https_prefix PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_includes_cortex_code PASSED tests/test_provider_cortex_code.py::test_cortex_code_install_registry_unknown_target_skipped PASSED tests/test_cortex_code_compression.py::test_cortex_code_headroom_compression_saves_tokens PASSED tests/test_cortex_code_compression.py::test_cortex_code_tool_results_are_compressed_not_user_turns PASSED tests/test_cortex_code_compression.py::test_cortex_code_tables_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_rag_search_json_compresses PASSED tests/test_cortex_code_compression.py::test_cortex_code_compression_is_lossless_on_key_content PASSED 20 passed, 1 warning in 1.91s ``` ## Real Behavior Proof - Environment: macOS, Python 3.11, headroom 0.27.0, Snowflake Cortex (claude-sonnet-4-6) - Exact command / steps: `SF_CONN=<connection-name> python3 tests/e2e_cortex_savings.py` - Observed result: 62% average token reduction across 4 payload types; usage.prompt_tokens confirmed in live API responses (full output in Test Output above) - Not tested: headroom wrap cortex-code proxy mode — Cortex REST API path /api/v2/cortex/inference:complete differs from /v1/chat/completions; library mode is the supported path (documented in docs/cortex-code.md Limitations) ```text Tokens saved : 22,077 prompt tokens (4 calls) Avg per call : 5,519 tokens / $0.01656 At 1k/day : $16.56/day | $6,044/year ``` ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Pre-commit hooks skipped locally due to a GPG signing / ruff-format stash conflict in the dev environment. `ruff check` passes clean on all new files. --------- Co-authored-by: Cortex Code <noreply@snowflake.com>
2026-06-21 22:18:47 -07:00
| Aider | ✅ | starts proxy + launches |
| Copilot CLI | ✅ | starts proxy + launches |
| OpenClaw | ✅ | installs as ContextEngine plugin |
docs: list OpenCode in the agent compatibility matrix (#1286) (#1340) ## Description #1286 asks whether OpenCode is supported and, if so, to update the README. It already is. `headroom wrap opencode` is a real, registered subcommand backed by a full `headroom/providers/opencode/` module (config injection, install, runtime) with test coverage (`tests/test_providers_opencode_*`, `tests/test_cli/test_wrap_opencode.py`, `tests/test_mcp_registry_opencode.py`, etc.). It's also in the agent-savings target set alongside claude/codex/cursor. The gap was purely docs: the agent compatibility matrix and the wrap one-liner never listed OpenCode, so users reasonably assumed it wasn't supported. Closes #1286 ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Added an OpenCode row to the agent compatibility matrix in the README. The note ("injects config · starts proxy + launches") reflects how the wrap actually works — it sets `OPENCODE_CONFIG_CONTENT` to route OpenCode's API calls through the proxy, then launches it. - Added `opencode` to the `headroom wrap claude|codex|cursor|aider|copilot|...` one-liner near the top of the README. - Fixed the wrap list in `llms.txt`: it advertised `gemini`, which is not a registered wrap subcommand, and left out `opencode`. The registered set is `aider claude cline codex continue copilot cursor goose openclaw opencode openhands vibe`. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed Docs-only change, so no new tests. I verified the claim against the code rather than just trusting it. ### Test Output ```text # Registered `headroom wrap` subcommands (source of truth for the matrix): $ python -c "from headroom.cli.wrap import wrap; print(sorted(wrap.commands.keys()))" ['aider', 'claude', 'cline', 'codex', 'continue', 'copilot', 'cursor', 'goose', 'openclaw', 'opencode', 'openhands', 'vibe'] # opencode is present; gemini is not. ``` ## Real Behavior Proof - Environment: Windows 11, local clone of main. - Exact command / steps: enumerated the registered Click subcommands under `headroom wrap` (above) and confirmed `headroom/providers/opencode/` exists with config/install/runtime modules and tests. - Observed result: `opencode` is a real registered wrap target with provider plumbing and tests; the only thing missing was its mention in the docs, which this PR adds. - Not tested: a live `headroom wrap opencode` launch against an actual OpenCode install — I don't have OpenCode set up here. The wrap path itself is already covered by the existing opencode test suite in this repo. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - No code change, so no new test and no CHANGELOG entry — the `docs:` commit is picked up by release-please on its own. - I deliberately didn't touch the dedicated `docs/cortex-code.md` page or anything beyond the matrix; this PR is scoped to making OpenCode discoverable in the docs.
2026-06-24 01:09:40 +05:30
| OpenCode | ✅ | injects config · starts proxy + launches |
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
| Cline | ✅ | starts proxy + injects config |
| Continue | ✅ | starts proxy + injects config |
| Goose | ✅ | starts proxy + launches |
| OpenHands | ✅ | starts proxy + launches |
| Mistral Vibe | ✅ | starts proxy + launches |
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
| Cortex Code | Library only | 6065% savings (library mode; no `wrap`) |
Any OpenAI-compatible client works via `headroom proxy`. MCP-native: `headroom mcp install`.
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
Undo durable wrapping with `headroom unwrap <tool>` (supports: `claude`, `copilot`, `codex`, `opencode`, `openclaw`).
### GitHub Copilot CLI subscription mode
Headroom can route GitHub Copilot CLI subscription traffic through the local proxy:
```bash
fix: support Copilot Business subscription auth (#641) ## Description Adds a first-party `headroom copilot-auth login` flow for Copilot subscription mode and uses the resulting Copilot OAuth token to perform GitHub's Copilot token exchange before launching the wrapped Copilot CLI. This fixes Business/Enterprise Cloud accounts where a generic GitHub/Copilot token can read Copilot account metadata but is rejected by the Copilot token exchange endpoint. It also avoids treating GitHub.com Enterprise Cloud account URLs such as `github.com/enterprises/acme` as API hostnames. Fixes #635 Related: #488, #610 Builds on #576 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Adds `headroom copilot-auth login` and `headroom copilot-auth status`. - Stores a Headroom-specific Copilot OAuth token under Headroom's state dir. - Exchanges reusable Copilot OAuth tokens with Copilot Chat-compatible headers before subscription-mode launch. - Carries the resolved Copilot API endpoint into `headroom wrap copilot --subscription`. - Handles GitHub.com Enterprise Cloud URLs without synthesizing invalid `api.github.com/enterprises/...` hosts. - Adds focused unit tests and README guidance for subscription login. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```console ruff check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # All checks passed! ruff format --check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # 9 files already formatted python -m py_compile headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py uv run --no-project --with pytest --with pytest-asyncio --with click --with rich --with opentelemetry-api --with pydantic --with tiktoken --with 'litellm==1.82.3' --with fastapi --with uvicorn --with 'httpx[http2]' --with openai --with mcp --with magika --with zstandard --with websockets --with onnxruntime --with transformers --with watchdog --with sqlite-vec pytest tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_cli_proxy_env.py tests/test_copilot_subscription_smoke.py # 127 passed ``` Local note: `uv run pytest ...` against the project currently fails before running tests because `uv.lock` has an unrelated `gitpython` wheel/version mismatch. ## Manual Validation I tested this with an existing GitHub Copilot Business subscription associated with a GitHub.com Enterprise Cloud account. The Enterprise Cloud value I tested was in the form: ```text github.com/enterprises/<enterprise> ``` The tested flow was: ```text headroom copilot-auth login headroom wrap copilot --subscription -- --model gpt-5.4 ``` This validated that Headroom does not treat github.com/enterprises/<enterprise> as a Copilot API hostname. Instead, token exchange uses GitHub.com and Headroom routes subscription-mode traffic to the Copilot API endpoint returned by GitHub for the signed-in account. I did not test this with GitHub Enterprise Server or a custom enterprise domain such as ghe.example.com. No tokens, request IDs, or organization-specific identifiers are included in this PR. ## Real Behavior Proof - Environment: macOS Darwin, Python 3.12.7, local checkout on `codex/copilot-business-auth`. - Exact command / steps: Ran `headroom copilot-auth login`, then launched `headroom wrap copilot --subscription -- --model gpt-5.4` with a GitHub Copilot Business subscription tied to a GitHub.com Enterprise Cloud account. - Observed result: Headroom did not treat `github.com/enterprises/<enterprise>` as a Copilot API hostname; token exchange used GitHub.com and subscription traffic was routed to the Copilot API endpoint returned for the signed-in account. The latest focused Copilot auth/proxy tests pass locally (`127 passed`). - Not tested: GitHub Enterprise Server or custom enterprise domains such as `ghe.example.com`; Windows Credential Manager integration still needs confirmation from someone on Windows. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing targeted unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A ## Additional Notes Acknowledgement: the OAuth/token-exchange behavior was informed by `anomalyco/opencode-copilot-auth` by Aiden Cline. No tokens are printed by the new login/status commands; only a short SHA-256 fingerprint is displayed for troubleshooting. The interactive login is included because the missing piece is not just an Enterprise URL or routing hint. For GitHub.com Enterprise Cloud accounts, URLs like `github.com/enterprises/acme` identify the enterprise account but are not Copilot API hostnames; token exchange still happens through GitHub.com and then returns the account-specific Copilot API endpoint. A command-line enterprise argument can help for true GitHub Enterprise Server/custom-domain deployments, but it cannot produce the Copilot OAuth token class that the token-exchange endpoint accepts. Ideally, Headroom would avoid an extra interactive login and reuse an existing GitHub/Copilot CLI session everywhere. In practice, some reusable-looking tokens can read Copilot account metadata but are rejected by Copilot token exchange, which leaves Business/Enterprise Cloud users with missing model catalogs. The explicit login command is the smallest independent way to obtain and persist the token needed for that exchange without asking users to pass a secret on the command line. --------- Co-authored-by: jbelanger <your-username@users.noreply.github.com>
2026-06-12 21:46:38 -04:00
headroom copilot-auth login
headroom wrap copilot --subscription -- --model gpt-4o
```
fix: support Copilot Business subscription auth (#641) ## Description Adds a first-party `headroom copilot-auth login` flow for Copilot subscription mode and uses the resulting Copilot OAuth token to perform GitHub's Copilot token exchange before launching the wrapped Copilot CLI. This fixes Business/Enterprise Cloud accounts where a generic GitHub/Copilot token can read Copilot account metadata but is rejected by the Copilot token exchange endpoint. It also avoids treating GitHub.com Enterprise Cloud account URLs such as `github.com/enterprises/acme` as API hostnames. Fixes #635 Related: #488, #610 Builds on #576 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Adds `headroom copilot-auth login` and `headroom copilot-auth status`. - Stores a Headroom-specific Copilot OAuth token under Headroom's state dir. - Exchanges reusable Copilot OAuth tokens with Copilot Chat-compatible headers before subscription-mode launch. - Carries the resolved Copilot API endpoint into `headroom wrap copilot --subscription`. - Handles GitHub.com Enterprise Cloud URLs without synthesizing invalid `api.github.com/enterprises/...` hosts. - Adds focused unit tests and README guidance for subscription login. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```console ruff check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # All checks passed! ruff format --check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # 9 files already formatted python -m py_compile headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py uv run --no-project --with pytest --with pytest-asyncio --with click --with rich --with opentelemetry-api --with pydantic --with tiktoken --with 'litellm==1.82.3' --with fastapi --with uvicorn --with 'httpx[http2]' --with openai --with mcp --with magika --with zstandard --with websockets --with onnxruntime --with transformers --with watchdog --with sqlite-vec pytest tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_cli_proxy_env.py tests/test_copilot_subscription_smoke.py # 127 passed ``` Local note: `uv run pytest ...` against the project currently fails before running tests because `uv.lock` has an unrelated `gitpython` wheel/version mismatch. ## Manual Validation I tested this with an existing GitHub Copilot Business subscription associated with a GitHub.com Enterprise Cloud account. The Enterprise Cloud value I tested was in the form: ```text github.com/enterprises/<enterprise> ``` The tested flow was: ```text headroom copilot-auth login headroom wrap copilot --subscription -- --model gpt-5.4 ``` This validated that Headroom does not treat github.com/enterprises/<enterprise> as a Copilot API hostname. Instead, token exchange uses GitHub.com and Headroom routes subscription-mode traffic to the Copilot API endpoint returned by GitHub for the signed-in account. I did not test this with GitHub Enterprise Server or a custom enterprise domain such as ghe.example.com. No tokens, request IDs, or organization-specific identifiers are included in this PR. ## Real Behavior Proof - Environment: macOS Darwin, Python 3.12.7, local checkout on `codex/copilot-business-auth`. - Exact command / steps: Ran `headroom copilot-auth login`, then launched `headroom wrap copilot --subscription -- --model gpt-5.4` with a GitHub Copilot Business subscription tied to a GitHub.com Enterprise Cloud account. - Observed result: Headroom did not treat `github.com/enterprises/<enterprise>` as a Copilot API hostname; token exchange used GitHub.com and subscription traffic was routed to the Copilot API endpoint returned for the signed-in account. The latest focused Copilot auth/proxy tests pass locally (`127 passed`). - Not tested: GitHub Enterprise Server or custom enterprise domains such as `ghe.example.com`; Windows Credential Manager integration still needs confirmation from someone on Windows. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing targeted unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A ## Additional Notes Acknowledgement: the OAuth/token-exchange behavior was informed by `anomalyco/opencode-copilot-auth` by Aiden Cline. No tokens are printed by the new login/status commands; only a short SHA-256 fingerprint is displayed for troubleshooting. The interactive login is included because the missing piece is not just an Enterprise URL or routing hint. For GitHub.com Enterprise Cloud accounts, URLs like `github.com/enterprises/acme` identify the enterprise account but are not Copilot API hostnames; token exchange still happens through GitHub.com and then returns the account-specific Copilot API endpoint. A command-line enterprise argument can help for true GitHub Enterprise Server/custom-domain deployments, but it cannot produce the Copilot OAuth token class that the token-exchange endpoint accepts. Ideally, Headroom would avoid an extra interactive login and reuse an existing GitHub/Copilot CLI session everywhere. In practice, some reusable-looking tokens can read Copilot account metadata but are rejected by Copilot token exchange, which leaves Business/Enterprise Cloud users with missing model catalogs. The explicit login command is the smallest independent way to obtain and persist the token needed for that exchange without asking users to pass a secret on the command line. --------- Co-authored-by: jbelanger <your-username@users.noreply.github.com>
2026-06-12 21:46:38 -04:00
This lets Headroom intercept OpenAI-compatible Copilot CLI requests and apply the same proxy compression pipeline before forwarding to GitHub Copilot's hosted API. The wrapper exchanges Headroom's reusable GitHub OAuth token for Copilot's short-lived API token and prints the upstream endpoint as `COPILOT_PROVIDER_API_URL=...` during launch.
`headroom copilot-auth login` stores a Headroom-specific Copilot OAuth token.
This avoids relying on generic GitHub or Copilot CLI tokens that can read
Copilot account metadata but may still be rejected by Copilot's token-exchange
endpoint.
For GitHub Enterprise Server or custom-domain Copilot deployments, set the
deployment domain before launching:
```bash
export GITHUB_COPILOT_ENTERPRISE_DOMAIN=ghe.example.com
```
For GitHub.com Enterprise Cloud URLs such as
`github.com/enterprises/your-enterprise`, do not set an enterprise-domain
override. Headroom uses GitHub's normal token-exchange endpoint and the Copilot
API endpoint advertised for the signed-in account.
Platform support note: macOS auth reuse via Copilot CLI Keychain storage has been smoke-tested. Windows Credential Manager, Linux Secret Service / `secret-tool`, and Docker/CI token-injection paths are implemented or planned as auth-discovery paths, but still need real OS validation before they should be considered fully vetted. For Docker and CI, prefer passing an explicit `GITHUB_COPILOT_TOKEN` or `GITHUB_COPILOT_GITHUB_TOKEN` rather than relying on host keychain access.
## When to use · When to skip
**Great fit if you…**
- run AI coding agents daily and want savings without changing your code
- work across multiple agents and want shared memory
fix(ccr): make retrieval TTL configurable (#715) ## Description Make the CCR retrieval store TTL configurable so long-running agent jobs can keep `headroom_retrieve` markers resolvable beyond the previous hard-coded 300-second window. Fixes #714 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Add `HEADROOM_CCR_TTL_SECONDS` for the global CCR `CompressionStore` default TTL, with validation and fallback to 300 seconds. - Expose the effective CCR TTL as `store.default_ttl_seconds` from `/v1/retrieve/stats`. - Distinguish missing vs expired CCR retrieval failures in `/v1/retrieve`, `/v1/retrieve/{hash}`, tool-call handling, and CCR response handling. - Update CCR docs, README wording, and CHANGELOG for the user-facing TTL behavior. - Add regression tests for env-configured TTL, invalid env fallback, explicit TTL precedence, stats exposure, and expired retrieval detail. ## Reproduction Before this change, the proxy-global CCR store always used the default 300-second TTL when callers used `get_compression_store()` without an explicit `default_ttl`. A long-running agent job could receive a `<<ccr:...>>` marker and fail later with a generic not-found/expired response after the fixed 5-minute retention window. The new tests cover this by setting `HEADROOM_CCR_TTL_SECONDS`, creating CCR entries through the same global store used by the proxy, and asserting that stored entries and `/v1/retrieve/stats` use the configured retention. ## Real behavior proof Setup tested: - macOS 15.7.2 - Python 3.13.9 via `uv run --frozen --extra dev --extra proxy` - Local Headroom proxy subprocess: `python -m headroom.proxy.server` - Proxy config: `HEADROOM_TELEMETRY=off`, `HEADROOM_CACHE_ENABLED=false`, `HEADROOM_RATE_LIMIT_ENABLED=false` - Provider/model: no live upstream provider needed; exercised local `/v1/compress` -> `/v1/retrieve` CCR HTTP flow with model `gpt-4o` Exact steps run after the patch: 1. Start a real Headroom proxy process with `HEADROOM_CCR_TTL_SECONDS=7200`. 2. POST a 200-item tool-result payload to `/v1/compress`. 3. Extract the emitted `<<ccr:...>>` marker hash from the compressed messages. 4. GET `/v1/retrieve/stats`. 5. POST `/v1/retrieve` with the marker hash. 6. Repeat with `HEADROOM_CCR_TTL_SECONDS=1`, wait 1.5 seconds, and retrieve the same way to verify explicit expiration reporting. Observed result: ```json { "long_ttl": { "ccr_hash": "b473e632aa47", "retrieve_status": 200, "retrieved_content_has_result_199": true, "stats_default_ttl_seconds": 7200, "stats_entry_count": 1, "ttl_seconds": 7200 }, "short_ttl_expired": { "ccr_hash": "b473e632aa47", "retrieve_detail": "Entry expired (CCR TTL: 1 seconds; age: 2 seconds)", "retrieve_status": 404, "stats_default_ttl_seconds": 1, "stats_entry_count": 1, "ttl_seconds": 1 } } ``` What I did not test: - A live OpenRouter/OpenAI/Anthropic upstream request. - A durable/non-memory CCR backend. - A literal 5+ minute wall-clock wait; the process E2E used `7200` to prove configured retention and `1` second to prove expiration behavior quickly. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ## Test Output ```bash UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_compression_store.py tests/test_proxy_ccr.py tests/test_ccr_response_handler.py tests/test_ccr_response_handler_extra.py # 152 passed, 2 warnings in 12.87s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_adapter_hooks.py tests/test_toin_feedback.py tests/test_toin_fixes.py # 55 passed, 13 skipped, 1 warning in 0.53s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff check . # All checks passed! UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff format --check . # 776 files already formatted UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy mypy headroom # Success: no issues found in 346 source files ``` Existing warnings observed in the targeted tests were unrelated to this change: - AnthropicProvider tiktoken approximation warning in proxy CCR tests. - Deprecated `ToolIntelligenceNetwork.get_recommendation()` warning in existing TOIN assertions. ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) Not applicable. ## Additional Notes No new dependencies. Default behavior remains 300 seconds unless `HEADROOM_CCR_TTL_SECONDS` is set.
2026-06-11 13:20:46 +09:00
- need reversible compression — originals are retrievable via CCR within the configured TTL
**Skip it if you…**
- only use a single provider's native compaction and don't need cross-agent memory
- work in a sandboxed environment where local processes can't run
<details>
<summary><b>Integrations — drop Headroom into any stack</b></summary>
| Your setup | Hook in with |
|------------------------|------------------------------------------------------------------|
| Any Python app | `compress(messages, model=…)` |
| Any TypeScript app | `await compress(messages, { model })` |
| Anthropic / OpenAI SDK | `withHeadroom(new Anthropic())` · `withHeadroom(new OpenAI())` |
| Vercel AI SDK | `wrapLanguageModel({ model, middleware: headroomMiddleware() })` |
| LiteLLM | `litellm.callbacks = [HeadroomCallback()]` |
| LangChain | `HeadroomChatModel(your_llm)` |
| Agno | `HeadroomAgnoModel(your_model)` |
| Strands | [Strands guide](https://headroom-docs.vercel.app/docs/strands) |
| ASGI apps | `app.add_middleware(CompressionMiddleware)` |
| Multi-agent | `SharedContext().put / .get` |
| MCP clients | `headroom mcp install` |
</details>
<details>
<summary><b>What's inside</b></summary>
- **SmartCrusher** — universal JSON: arrays of dicts, nested objects, mixed types.
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
- **CodeCompressor** — AST-aware for Python, JS/TS, Go, Rust, Java, C/C++, Perl.
- **Kompress-v2-base** — our HuggingFace model, trained on agentic traces.
- **Image compression** — 4090% reduction via trained ML router.
- **CacheAligner** — stabilizes prefixes so Anthropic/OpenAI KV caches actually hit.
- **CCR** — reversible compression; LLM retrieves originals on demand.
- **Cross-agent memory** — shared store, agent provenance, auto-dedup.
- **SharedContext** — compressed context passing across multi-agent workflows.
- **`headroom learn`** — plugin-based failure mining for Claude, Codex, Gemini.
</details>
<details>
<summary><b>Pipeline internals</b></summary>
Headroom exposes one stable request lifecycle across `compress()`, the SDK, and the proxy:
`Setup``Pre-Start``Post-Start``Input Received``Input Cached``Input Routed``Input Compressed``Input Remembered``Pre-Send``Post-Send``Response Received`
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
- **Transforms** do the work: CacheAligner, ContentRouter, SmartCrusher, CodeCompressor, Kompress-v2-base.
- **Pipeline extensions** observe or customize lifecycle stages via `on_pipeline_event(...)`.
- **Compression hooks** sit alongside the canonical lifecycle as an additional extension seam.
- **Proxy extensions** remain the server/app integration seam for ASGI middleware, routes, and startup policy.
Provider and tool-specific behavior lives under `headroom/providers/` so core orchestration stays focused on lifecycle, sequencing, and policy.
- **CLI/tool slices**: `headroom/providers/claude`, `copilot`, `codex`, `openclaw`
- **Provider runtime slices**: `headroom/providers/claude`, `gemini`, plus shared backend/runtime dispatch in `headroom/providers/registry.py`
- **Core files stay orchestration-first**: `wrap.py`, `client.py`, `cli/proxy.py`, and `proxy/server.py` delegate provider-specific env shaping, API target normalization, backend selection, and transport dispatch.
</details>
docs(readme): add "Headroom for teams" inbound for companies (#1529) ## Description Adds a "Headroom for teams" inbound section to the README. Headroom OSS is great for individual developers running it on their laptops, but companies running LLM agents (Claude Code, Codex, Cursor, CI agents) across an org want a deployed/supported/managed option. This creates a clear, OSS-respecting inbound: a CTA directing teams to `hello@headroomlabs.ai` with their stack + monthly LLM spend. Placed at the natural "self-install vs. talk to us" fork — after "When to use · When to skip", before "Install" — and reaffirms Apache 2.0 so the open-source promise stays explicit. Closes # (no tracking issue) ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README.md: new `## Headroom for teams` section with a managed/self-hosted-at-scale value prop and a `mailto:hello@headroomlabs.ai` CTA. ## Testing - [ ] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text # README-only change — no code/tests affected. Verified the section renders # and the mailto link is correct: $ sed -n '/## Headroom for teams/,/## Install/p' README.md ## Headroom for teams ... → Email [hello@headroomlabs.ai](mailto:hello@headroomlabs.ai) ... ``` ## Real Behavior Proof - Environment: README documentation change only — no runtime behavior. - Exact command / steps: added the section between the "When to use · When to skip" and "Install" headings; verified the rendered markdown and the mailto link with `sed -n '/## Headroom for teams/,/## Install/p' README.md`. - Observed result: the section renders correctly with a working `mailto:hello@headroomlabs.ai` CTA; no other README content changed; no code paths touched. - Not tested: N/A — documentation-only change, the behavioral test suite is unaffected. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - Intentional, polished commercial inbound — distinct from the stray internal "managed platform" planning docs removed in the repo-cleanup PR (#1528). - Follow-up option: add a "Teams" link to the README header nav for extra visibility. Deferred here to avoid colliding with #1528's nav edit; easy to add conflict-free once that merges.
2026-06-27 23:28:23 -07:00
## Headroom for teams
Headroom OSS is built for **individual developers**: run `headroom proxy` or `headroom wrap` on your laptop and start cutting tokens in minutes — free, local-first, your data never leaves your machine.
Running it across a **whole engineering org** is a different job: a shared, always-on deployment; centralized config and version rollout; org-wide savings dashboards; SSO and access controls; air-gapped / VPC installs; and someone to call when it matters. That's what we help companies with — self-hosted with support, or fully managed.
**If your team is spending real money on LLM tokens** — Claude Code, Codex, Cursor, or agents running in CI — **and you want those savings across everyone, not just one laptop:**
→ Email **[hello@headroomlabs.ai](mailto:hello@headroomlabs.ai)** with your stack and rough monthly LLM spend, and we'll help you roll Headroom out across your organization.
Everything in this repo stays open source (Apache 2.0). The managed offering is simply for teams that would rather have it deployed, supported, and scaled for them.
## Install
```bash
docs: clarify the headroom CLI is pip-only; npm headroom-ai is the TS SDK (#1585) ## Description `npm install headroom-ai` doesn't give you the `headroom` CLI — it's the TypeScript SDK (a library, no `bin`). The README's "Get started" and "Install" blocks listed the npm install next to the pip install and then immediately ran `headroom wrap claude`, so Node/Windows users reasonably expected npm to provide the CLI and hit `'headroom' is not recognized`. This spells out the split: CLI = pip, SDK = npm. The hnswlib/MSVC half of the report was already fixed on main in #1499 (moved hnswlib to the optional `[vector]` extra), so this PR only addresses the npm-CLI confusion. Closes #1470 ## Type of Change - [x] Documentation update ## Changes Made - README "Get started" + "Install" blocks: annotate that pip ships the `headroom` CLI and npm `headroom-ai` is the TS SDK with no CLI; note the `headroom` commands come from the pip install. - `docs/content/docs/installation.mdx`: state the TS SDK does not install the `headroom` CLI. ## Testing - [x] Manual testing performed ### Test Output ```text Docs-only change. Verified against the source of truth: - pyproject.toml: [project.scripts] headroom = "headroom.cli:main" (CLI entry point is Python-only) - sdk/typescript/package.json: name "headroom-ai", no "bin" field (SDK, no CLI) ``` ## Real Behavior Proof - Environment: repo main @ HEAD - Exact command / steps: read `[project.scripts]` in pyproject.toml and the `bin` field in sdk/typescript/package.json - Observed result: `headroom` console script is defined only by the Python package; the npm package has no `bin`, so `npm install headroom-ai` provides no `headroom` command — matching the issue. - Not tested: n/a (no code paths changed) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings
2026-06-30 21:17:47 +05:30
pip install "headroom-ai[all]" # Python, everything — includes the `headroom` CLI
npm install headroom-ai # TypeScript SDK (library only — no `headroom` CLI)
docker pull ghcr.io/chopratejas/headroom:latest
```
docs: sync README + benchmarks with code (drop retired IntelligentContext/RollingWindow) (#1545) ## Description Sync the docs with the code after the live-zone realignment. The `IntelligentContextManager` (ICM), `RollingWindow`, and scoring modules were deleted in PR #350 (May 2026), but the README and benchmark docstrings still advertised them as live, and an example still imported the deleted module (broken on run). This fixes the README + benchmarks and removes the dead example. I validated the README against the code with three parallel static-analysis sub-agents (features/architecture, CLI/extras/wrap-matrix, public API/integrations). Most of the README checked out accurate; only the items below were stale/wrong. Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - README: removed the `IntelligentContext` bullet and `IntelligentContext / RollingWindow` from the transforms list (both deleted in PR #350). - README: standardized `Kompress-base` -> `Kompress-v2-base` to match the HF model id `chopratejas/kompress-v2-base` and the existing badges (diagram re-aligned). - README: corrected the CodeCompressor language list to match the `CodeLanguage` enum (added TS, C, Perl). - README: softened the unanchored "6 algorithms" tagline to "content-aware compressors". - README: Cortex Code is library-mode only — there is no `headroom wrap cortex`, so the compatibility-matrix row no longer shows a wrap checkmark. - Deleted `examples/test_intelligent_context_toin_ccr.py` — it imported the deleted `IntelligentContextManager` (ImportError on run) and is unreferenced. - Removed stale `RollingWindow` mentions from benchmark docstrings/comments (`benchmarks/__init__.py`, `bench_transforms.py`, `bench_latency.py`, `scenarios/conversations.py`); the accurate PR-B1 retirement comment is kept. ## Testing - [ ] Unit tests pass (`pytest`) — N/A, docs/docstring + example deletion only - [x] Linting passes — `ruff check` clean on all changed benchmark files - [ ] Type checking passes — N/A (no type-relevant changes) - [ ] New tests added — N/A - [x] Manual testing performed — see Real Behavior Proof ### Test Output ```text $ ruff check benchmarks/__init__.py benchmarks/bench_transforms.py benchmarks/bench_latency.py benchmarks/scenarios/conversations.py All checks passed! # stale refs remaining in README/benchmarks (excluding accurate retirement notes): $ grep -rn "IntelligentContext|RollingWindow|Kompress-base" README.md benchmarks/ | grep -v retire (only benchmarks/bench_transforms.py:362 — the accurate PR-B1 retirement comment) # deleted example is unreferenced anywhere: $ grep -rn "test_intelligent_context_toin_ccr" --include=*.md --include=*.yml --include=*.py . (no hits) ``` ## Real Behavior Proof - Environment: macOS (darwin, arm64), Python 3.12 `.venv`, ruff 0.14.x, repo at branch `docs/sync-readme-with-code` off latest `main`. - Exact command / steps: (1) three parallel sub-agents grep/Read-validated README claims vs `headroom/`, `pyproject.toml`, `sdk/typescript/`; (2) directly verified each flagged mismatch (`CodeLanguage` enum, `HF_MODEL_ID`, absence of `IntelligentContext`/`RollingWindow` classes); (3) confirmed the example imports a deleted module and is unreferenced; (4) `ruff check` on changed benchmark files; (5) re-grepped README + benchmarks for any remaining stale refs. - Observed result: README and benchmark docstrings now match the code; the only surviving `RollingWindow` string is the accurate retirement comment; the broken example is removed; ruff passes; the ASCII architecture diagram still aligns after the `Kompress-v2-base` rename. - Not tested: rendering of the README on GitHub/PyPI (text-only change); the separate `docs/content/` and `wiki/` doc sets (see Additional Notes — out of scope for this PR). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective — N/A (docs/example cleanup) - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md — N/A (Release Please auto-generates from the conventional commit) ## Additional Notes **Larger related finding (NOT in this PR):** the published docs site (`docs/content/docs/*.mdx`) and the `wiki/*.md` set still document `IntelligentContextManager`, `RollingWindow`, `RollingWindowConfig`, `IntelligentContextConfig`, and `ScoringWeights` as live API — with `from headroom import RollingWindow` / `from headroom.transforms import IntelligentContextManager` code examples that would `ImportError`. It is half-migrated (a couple of `.mdx` files already note "removed in 0.9.x" while neighbors still teach it as current). This is ~15 files and the fixes require rewriting examples to the live-zone model, not just deletions — recommended as a focused follow-up PR rather than bundling it here.
2026-06-28 22:36:41 -07:00
Granular extras: `[proxy]`, `[mcp]`, `[ml]` (Kompress-v2-base), `[code]`, `[memory]`, `[vector]` (optional HNSW backend — needs a C++ toolchain, not in `[all]`), `[relevance]`, `[image]`, `[agno]`, `[langchain]`, `[evals]`, `[pytorch-mps]` (Apple-GPU memory-embedder offload — set `HEADROOM_EMBEDDER_RUNTIME=pytorch_mps`). Requires **Python 3.10+**.
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
> **Note**: `[all]` covers the core stack but excludes framework adapters. Install them separately: `pip install "headroom-ai[langchain]"` (also `[agno]`, `[strands]`, `[anyllm]`, `[bedrock]`).
Using `pipx`? Choose a supported interpreter explicitly:
```bash
pipx install --python python3.13 "headroom-ai[all]"
```
fix: surface output reduction without a restart, and explain $0.00 savings on Python 3.14 (#1296) ## Description I was running headroom through pipx on Python 3.14 and hit two issues. The Proxy $ Saved tile was stuck at $0.00 even though tokens were tracking fine. Pricing comes from litellm, and litellm does not install on Python 3.14 because of a version lock, so there was just nothing to price against. Rather than hardcode a price table that goes stale, I added a `litellm_available` flag to `/stats` and the tile now tells you to reinstall on 3.13 when pricing isn't there, like the output-shaper tile already does. The other one was Output Tokens Saved showing "—" after I turned on the shaper. The recorder reads the learned baseline once at startup, so if you run `learn --verbosity --apply` while the proxy is already up it never gets picked up, and a later flush writes the empty baseline over the one learn just saved. Now it re-reads the baseline before estimating and before each flush, so it works without a restart. Closes # N/A (no tracking issue) ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `output_savings.py`: re-read the baseline from disk before estimating and before each flush, so a baseline learned while the proxy is running takes effect (and a re-learn with the same sample count too). - `server.py`: expose a `litellm_available` flag on `/stats`. - `dashboard.html`: when savings are zero and litellm is missing, point to reinstalling on 3.13 instead of showing $0.00. - tests and docs (`test_output_savings.py`, README, metrics, CHANGELOG). ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py -q 34 passed, 1 warning in 0.11s ``` ## Real Behavior Proof - Environment: macOS, Python 3.13 (litellm present) and 3.14 (litellm absent), running this branch. - Exact command / steps: record shaped traffic, write a baseline to the same file while the recorder is live (no restart), then estimate and flush. - Observed result: the recorder goes from `available: False` to `available: True` once the baseline is written mid-run, and keeps it after a flush. Before this it stayed `False` and the flush reset the baseline. Raw output: ```text shaper traffic recorded, baseline not learned yet -> available: False learn --apply wrote baseline while proxy up; restart NOT performed after baseline write -> available: True | method: estimated | pct: 50.3 baseline kept after flush -> disk samples: 4 ``` - Not tested: I did not render the tile hint in a browser, I checked the flag on `/stats` and read the template instead. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Additional Notes Just a final note, ruff and mypy are clean on what I changed. The repo-wide `ruff check .` and `mypy headroom` do report a few problems, but they're in files I didn't touch and already exist on the base commit, so I left them alone to keep this small. Happy to do a separate cleanup PR. --------- Co-authored-by: JD Davis <mxjerrett@gmail.com>
2026-06-26 19:15:42 +02:00
> **Pick 3.13 if you want dollar savings.** The dashboard's *Proxy $ Saved* tile prices compression with [LiteLLM](https://github.com/BerriAI/litellm), and LiteLLM can't be installed on Python 3.14+. On 3.14 token savings still track, but the dollar figure stays `$0.00`. If you already installed on 3.14, switch with `pipx reinstall headroom-ai --python python3.13` and restart the proxy.
→ [Installation guide](https://headroom-docs.vercel.app/docs/installation) — Docker tags, persistent service, PowerShell, devcontainers.
fix(relevance): gate ONNX embedding backend behind AVX2 to avoid SIGILL (#1723) (#1765) ## Description Fixes the `SIGILL` / Illegal instruction crash in `headroom.compress` on CPUs without AVX2 (Docker / QEMU / older cloud VMs). The precompiled ONNX Runtime binary shipped by `ort-sys` (via fastembed's `ort-download-binaries*` feature) contains AVX2-family instructions on x86; running it on a non-AVX2 CPU traps with SIGILL — an uncatchable native fault that kills the whole host process. Magika detection was already guarded (#1162, landed after `v0.28.0`); the embedding relevance scorer shared the same `ort-sys` binary with no guard. This PR closes that remaining entry point and documents the requirement. Closes #1723 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Add shared `onnx_cpu::onnx_runtime_supported_by_cpu()` helper (AVX2 check on x86/x86_64, `true` on other arches) as the single source of truth. - Route `magika_detector` through the shared helper (no behavior change). - Gate `EmbeddingScorer::try_new*` on the helper: unsupported CPU returns `Err` before touching ONNX, so callers fall back to BM25/stub instead of crashing. - Document the x86 AVX2 requirement + auto-fallback in the README. - Add offline tests (no network / no `RUN_FASTEMBED_TESTS`). ## Testing - [x] Unit tests pass (Rust: `cargo test -p headroom-core`) - [x] Linting passes (`cargo clippy -p headroom-core --all-targets`, `cargo fmt --check`) - [ ] Type checking passes (`mypy headroom`) — N/A, Rust-only change - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ cargo test -p headroom-core --lib relevance::embedding cargo test: 13 passed, 834 filtered out (1 suite, 0.00s) $ cargo test -p headroom-core --lib magika cargo test: 16 passed, 831 filtered out (1 suite, 0.16s) $ cargo clippy -p headroom-core --all-targets (no warnings, no errors) $ cargo fmt --check -p headroom-core (clean) $ cargo build --workspace cargo build (225 crates compiled) Finished `dev` profile [unoptimized + debuginfo] target(s) in 6m 57s ``` ## Real Behavior Proof - Environment: `headroom-core` workspace, Rust stable, x86_64 (AVX2-capable dev host). - Exact command / steps: added `onnx_guard_matches_cpu_features` and `try_new_errors_on_unsupported_cpu_instead_of_sigill` tests; ran the suites above. On a no-AVX2 host the guard makes `EmbeddingScorer::try_new()` return `Err(... "AVX2" ...)` instead of executing the AVX2 ONNX binary; callers fall back to BM25 relevance rather than crashing. - Observed result: guard returns `false` only when the CPU lacks AVX2; embedding + magika ONNX paths both short-circuit to non-ONNX fallbacks; no SIGILL. All suites green. - Not tested: end-to-end `pip install` run on a physically AVX2-less machine (dev host has AVX2); guard behavior is unit-tested via the shared `onnx_cpu` helper and mirrors the already-shipped magika guard (#1162). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable — N/A (release-please generates the changelog) ## Additional Notes Rust-only change, so the Python `pytest`/`ruff`/`mypy` items are N/A; equivalent Rust `cargo test`/`clippy`/`fmt` were run and pasted above. The fix is defense-in-depth parity with the existing magika AVX2 guard (#1162), applied to the second ONNX entry point (embedding relevance). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 21:10:34 +02:00
> **CPU requirement (x86/x86_64):** the ONNX-backed features — Magika content
> detection and embedding relevance — use a precompiled ONNX Runtime that needs
> **AVX2**. On x86 hosts without AVX2 (some Docker/QEMU setups and older cloud
> VMs) Headroom automatically falls back to its non-ONNX paths (BM25 relevance,
> heuristic detection) rather than crashing. `arm64`/Apple Silicon needs no AVX2.
feat(cli): add headroom update command and release banner (#1088) ## Description Adds a `headroom update` self-update command and a passive "update available" banner, so users no longer need to remember the right `pip`/`pipx`/`uv` incantation for their environment, and long-running proxies get nudged when they drift behind a release. Closes #1087 ## Type of Change - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update ## Changes Made - `headroom/cli/update.py` — `headroom update` command. `detect_install_method()` resolves the install (git checkout, editable, Docker, pipx, uv tool, venv/conda, `pip --user`, externally-managed system Python per PEP 668, writable global) and builds the matching upgrade. pip path always uses `sys.executable -m pip` so it can't touch the wrong interpreter. Refuses with guidance where self-update is unsafe. Flags: `--check`, `--yes`, `--pre`, `--extras`. - `headroom/update_check.py` — best-effort PyPI check (stdlib `urllib`, no new dep). Split into a daemon-thread probe that caches to `~/.headroom/update_check.json` (≤ once/day) and a cache-only `format_update_notice()`. Opt-out `HEADROOM_UPDATE_CHECK=off`; skipped in `--stateless`, CI, Docker, checkouts. - `headroom/cli/main.py`, `headroom/cli/__init__.py` — register `update`; fire the background check from the group callback (skipped for `update`). - `headroom/cli/proxy.py` — render the one-line notice after the startup banner (best-effort, never blocks). - `README.md` — "Updating" section + opt-out env var. - Tests: `tests/test_update_check.py`, `tests/test_cli_update.py`. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_update_check.py tests/test_cli_update.py -q 42 passed in 1.63s $ ruff check headroom/cli/update.py headroom/update_check.py headroom/cli/main.py All checks passed! $ mypy headroom/update_check.py headroom/cli/update.py Success: no issues found in 2 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.11, source checkout - Exact command / steps: `python -m headroom.cli update --help`; `detect_install_method()` in the checkout - Observed result: command + flags render; in a checkout `detect_install_method()` returns `kind=checkout, can_self_update=False` ("update with `git pull`") and `format_update_notice()` returns `None` (dev tree not nagged) - Not tested: live PyPI fetch and a real pipx/uv-tool upgrade on this machine (covered by unit tests with mocked `urllib`/`subprocess`) ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - CHANGELOG.md is release-please-managed, so it is intentionally not hand-edited (N/A above). - Update check uses stdlib `urllib` because `httpx` lives only in the `[proxy]` extra — the base CLI must stay dependency-light.
2026-06-18 18:22:20 +02:00
### Updating
```bash
headroom update # detects pip / pipx / uv tool and upgrades in place
headroom update --check # report the latest release without upgrading
headroom update --pre # include pre-releases
```
`headroom update` figures out how Headroom was installed (pip/venv, `pip --user`,
pipx, uv tool) and runs the matching upgrade across macOS, Linux, and Windows.
For git checkouts, editable installs, Docker images, and externally-managed
system Pythons (PEP 668) it prints the correct manual step instead of guessing.
The proxy also shows a one-line "update available" notice on startup. It checks
PyPI at most once a day, in the background, and never blocks. Opt out with
`HEADROOM_UPDATE_CHECK=off` (also skipped in `--stateless` mode and CI).
### Corporate / SSL-inspection environments
If `pip install "headroom-ai[all]"` fails with `CERTIFICATE_VERIFY_FAILED`
(`unable to get local issuer certificate`), your network uses **SSL inspection** — a MITM
proxy presenting a company-issued CA. The build backend (`maturin`) downloads `rustup` over a
connection your TLS stack doesn't trust. **Install Rust first** so the build doesn't fetch it:
```bash
# macOS / Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && rustup default stable
# Windows
winget install Rustlang.Rustup && rustup default stable
```
Restart your shell, then `pip install "headroom-ai[all]"`. A prebuilt wheel avoids the Rust
ci(release): publish win_amd64 wheel so Windows installs need no Rust (#1328) (#1335) ## Description We ship wheels for macOS arm64 and manylinux x86_64/aarch64, but there's no `win_amd64` wheel on PyPI for any Python version. So on Windows, pip/uv can't find a binary and try to build from the sdist with maturin, which pulls the Rust toolchain from static.rust-lang.org and crates from crates.io. On locked-down machines (corporate proxies, CI runners, the GitHub Copilot CLI sandbox, anything air-gapped) those hosts aren't reachable and the install just dies: ``` error: could not download file from 'https://static.rust-lang.org/dist/channel-rust-stable.toml.sha256' error: failed to get pyo3-macros as a dependency of package pyo3 v0.24.2 [28] Timeout was reached (Failed to connect to index.crates.io port 443) ``` This adds the Windows wheel to the release matrix so `pip install headroom-ai` works on Windows without a local Rust install. Closes #1328 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Added a `windows-latest` / `x86_64-pc-windows-msvc` row to the `build-wheels` matrix. The runner already has MSVC and maturin-action sets up Rust, so it produces `headroom_ai-*-win_amd64.whl` on every release. I checked `crates/headroom-core/Cargo.toml` first — the Windows ONNX path is already on `ort-load-dynamic` under `cfg(windows)`, so the wheel loads ORT at runtime instead of linking the DirectML SDK libs. Nothing else was needed on the Rust side. - Added a matching `windows-latest` row to `smoke-import-wheels` so a broken Windows wheel blocks publish like the other platforms do. Windows needed its own step: the venv puts Python under `Scripts\` not `bin/`, and the runner defaults to pwsh. I also pinned the shared script-staging step to `shell: bash` since it uses a heredoc that pwsh can't run (Git Bash is on the runner), and added a `setup-python` step to get the right minor version. - Updated the README install section so the "install Rust first" workaround is clearly only for the sdist fallback (e.g. Intel macOS) now that Windows/Linux/macOS-arm64 all have prebuilt wheels. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed This is a CI workflow + docs change, no Python runtime code. I leaned on the existing `tests/test_release_workflows.py` structural gates plus a YAML parse and matrix-shape sanity check. ### Test Output ```text $ python -m pytest tests/test_release_workflows.py -q 28 passed, 1 skipped, 1 failed # The one failure, test_no_native_tls_in_wheel_build_tree, shells out to cargo, which # isn't installed here. I confirmed with `git stash` that it fails the same way on main # without my changes, so it's pre-existing and unrelated. $ python -c "import yaml; d=yaml.safe_load(open('.github/workflows/release.yml',encoding='utf-8')); \ j=d['jobs']; print('build-wheels rows:', len(j['build-wheels']['strategy']['matrix']['include'])); \ print('smoke rows:', len(j['smoke-import-wheels']['strategy']['matrix']['include']))" build-wheels rows: 4 smoke rows: 6 ``` ## Real Behavior Proof - Environment: Windows 11 local clone; CI runs on GitHub-hosted `windows-latest`. - Exact command / steps: edited the build-wheels and smoke-import-wheels matrices in `.github/workflows/release.yml` and the README, then ran the release-workflow tests and the YAML/matrix-shape check above. - Observed result: tests pass, YAML parses, build matrix is now 4 rows (Linux x64, Linux arm64, macOS arm64, Windows x64) and the smoke matrix is 6 rows including the new native Windows row. - Not tested: the actual win_amd64 build + PyPI publish. Those jobs only run in the release workflow on a tag or workflow_dispatch, not on a feature PR. The PR-time release dry-run will exercise the new rows once a maintainer approves the workflow run. I couldn't run `maturin build --target x86_64-pc-windows-msvc` end to end here. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - No new test file: the existing structural gates in `tests/test_release_workflows.py` (`test_build_wheels_matrix_excludes_intel_macos`, `test_aarch64_wheel_uses_native_arm64_runner`, the smoke-import gate test) already assert the matrix contract and still pass with the Windows row added. - I didn't touch CHANGELOG.md — release-please generates it from the Conventional Commit subject, so the `ci(release):` commit gets picked up automatically. - The win_amd64 wheel actually shows up on PyPI on the next tagged release.
2026-06-24 20:18:37 +05:30
build entirely where available: `pip install --only-binary headroom-ai headroom-ai`. Prebuilt
wheels are published for Windows (`win_amd64`), Linux (`x86_64` / `aarch64`), and macOS
fix(build): enable Intel macOS pip installs via ort-load-dynamic (#1538) ## Description Fix `pip install headroom-ai` on Intel Mac (`x86_64-apple-darwin`). Source installs failed because `ort-sys 2.0.0-rc.12` (transitive via `fastembed`) does not ship prebuilt ONNX Runtime binaries for that target, causing maturin/cargo to exit during the wheel build. This PR mirrors the existing Windows fix: build the Rust core with `ort-load-dynamic`, pin `ORT_DYLIB_PATH` to the pip `onnxruntime` native library at import time, and publish Intel macOS wheels from CI. Closes # ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `crates/headroom-core/Cargo.toml`: use `ort-load-dynamic` for `x86_64-apple-darwin` instead of `ort-download-binaries-rustls-tls`. - `headroom/_ort.py`: extend the ORT dylib pin hook to Intel macOS (`darwin` + `x86_64`), resolving `libonnxruntime*.dylib` from the pip `onnxruntime` package. - `.github/workflows/release.yml` and `.github/workflows/rust.yml`: add `macos-15-intel` / `x86_64-apple-darwin` wheel matrix entries. - `tests/test_release_workflows.py` and `tests/test_transforms/test_ort_dylib.py`: update/add coverage for the new target and dylib pin behavior. - `README.md`: note that prebuilt wheels are published for Intel macOS. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_transforms/test_ort_dylib.py \ tests/test_release_workflows.py::test_fastembed_uses_dynamic_ort_on_windows \ tests/test_release_workflows.py::test_build_wheels_matrix_includes_intel_macos_with_dynamic_ort -q .......................... [100%] 10 passed in 0.18s $ maturin build --release -o /tmp/headroom-dist 📦 Built wheel for abi3 Python ≥ 3.10 to /tmp/headroom-dist/headroom_ai-0.27.0-cp310-abi3-macosx_10_12_x86_64.whl $ python3.11 -m venv /tmp/hr-venv && /tmp/hr-venv/bin/pip install . Successfully built headroom-ai Successfully installed headroom-ai-0.27.0 $ cd /tmp && /tmp/hr-venv/bin/python -c "import headroom; import headroom._core; print('ok')" version 0.27.0 _core ok ``` ## Real Behavior Proof - Environment: macOS `x86_64-apple-darwin`, Python 3.11.5, Rust 1.95.0 - Exact command / steps: Reproduced the reported failure with `pip install headroom-ai` (sdist build dies in `ort-sys` for `x86_64-apple-darwin`); after this patch ran `maturin build --release`, then `pip install .` in a clean venv, then `python -c "import headroom._core"`. - Observed result: Before fix, cargo/maturin exit 101 on missing ORT prebuilts; after fix, wheel build succeeds and `headroom._core` imports cleanly (`version 0.27.0`, `_core ok`). - Not tested: `macos-15-intel` GitHub Actions wheel matrix row (will be validated by CI after merge). ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - ML features (magika detection, fastembed embeddings) still require `onnxruntime` at runtime on Intel Mac. Users should install `headroom-ai[proxy]` or `pip install onnxruntime`; `_ort.py` auto-pins `ORT_DYLIB_PATH` when that package is present. - Apple Silicon (`aarch64-apple-darwin`) behavior is unchanged: it continues to bundle ORT via `ort-download-binaries-rustls-tls`. - Lint/mypy not re-run locally in this pass; targeted pytest + maturin/pip install proof covers the changed surface. --------- Co-authored-by: Bor <you@example.com> Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 19:33:34 -04:00
(Apple Silicon and Intel), so installs on those platforms never need a local Rust toolchain — the
Rust-first dance above is only for the platform-independent sdist fallback when no wheel matches.
Two runtime assets are fetched over TLS; if they are blocked, trust your corporate CA via
`REQUESTS_CA_BUNDLE` / `SSL_CERT_FILE` / `CURL_CA_BUNDLE`:
- **`cdn.pyke.io`** — the ONNX Runtime for the Rust core. Alternatively pre-provide it with
`ORT_STRATEGY=system` and `ORT_LIB_LOCATION=/path/to/onnxruntime`.
- **`huggingface.co`** — the `kompress-base` compression model. Pre-download it and run with
`HF_HUB_OFFLINE=1`, or set `HF_ENDPOINT` to a trusted mirror.
Running with compression disabled (pure gateway) requires neither asset.
fix(tls): add HEADROOM_TLS_STRICT=0 toggle for corporate SSL inspection (#1308) (#1341) ## Description Behind a corporate TLS-inspection proxy (Zscaler, Netskope) on Python 3.13+, Headroom can't reach the network even with the corporate root correctly installed and trusted. Every path fails with: ``` [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Basic Constraints of CA cert not marked critical ``` This isn't a missing-CA problem — the cert is found and trusted. Python 3.13 + OpenSSL 3.x enable `VERIFY_X509_STRICT` by default, which enforces RFC 5280 §4.2.1.9 (a CA cert's `basicConstraints` MUST be marked critical). Inspection roots set `CA:TRUE` without the critical bit, so the chain is rejected. Adding the CA to a bundle does nothing — it's the strict check that fails, and the existing README section only covers `unable to get local issuer certificate`. There are two independent sources of the strict flag (both reported in the issue): Python's own `ssl.create_default_context()` (hits the httpx upstream client), and urllib3 ≥ 2.5's `create_urllib3_context()` (hits the `huggingface_hub` model-download path). Closes #1308 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `ssl_context.py`: added `HEADROOM_TLS_STRICT`. `tls_strict_disabled()` reads the toggle (off-values `0/false/no/off`, default strict). `build_httpx_verify()` resolves the httpx `verify=` value: a configured CA bundle wins; otherwise, when the toggle is off, a default-trust-store context with **only** `VERIFY_X509_STRICT` cleared (so a corporate root that lives in the OS store but trips strict mode still validates); otherwise `True` (httpx default). `apply_global_tls_relaxation()` monkeypatches urllib3's `create_urllib3_context` to drop the strict flag — idempotent, guarded, no-op if urllib3 is absent or the toggle is on. - `server.py`: the proxy's httpx upstream client now uses `build_httpx_verify()` instead of `find_ca_bundle()`-or-`True`. - `cli/proxy.py`: calls `apply_global_tls_relaxation()` at module import, before `huggingface_hub`/`requests` import and cache their context. - README: a distinct SSL-inspection subsection for the `Basic Constraints ... not marked critical` failure, separate from `unable to get local issuer certificate`. Documents that the Rust core's ONNX download (`cdn.pyke.io`) uses a separate stack (rustls/OS trust store) unaffected by the toggle — corporate root must be in the Windows **machine** store, or pre-provision via `ORT_STRATEGY=system`. Chain validation, signature, expiry, and hostname checks all stay on — `HEADROOM_TLS_STRICT=0` is strictly narrower than `verify=False`. Default is strict, matching Python's own default. ## Testing - [x] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text $ python -m pytest tests/test_ssl_context.py -q 31 passed # 19 existing + 12 new (TestTlsStrictDisabled, TestBuildHttpxVerify, TestApplyGlobalTlsRelaxation). ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.10.11 (OpenSSL build that exposes `VERIFY_X509_STRICT`). - Exact command / steps: exercised the module directly — set/unset `HEADROOM_TLS_STRICT`, inspected the resolved httpx `verify` value and the urllib3 context's `verify_flags`. - Observed result: default → `verify=True` (strict preserved); `HEADROOM_TLS_STRICT=0` → httpx gets an `SSLContext` with `VERIFY_X509_STRICT` cleared but `verify_mode == CERT_REQUIRED` and the full default trust store (cert_store x509_ca > 1); `apply_global_tls_relaxation()` patches `urllib3.util.ssl_.create_urllib3_context` so new contexts have the strict flag cleared, and is idempotent. A configured `SSL_CERT_FILE` still wins over the toggle. - Not tested: an actual handshake through a live Zscaler/Netskope MITM on Python 3.13 — I don't have that environment. The fix targets exactly the flag the issue identifies (`VERIFY_X509_STRICT`) on both reported context builders; I verified the flag manipulation and resolution logic directly rather than simulating the proxy. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes - The toggle is opt-in and defaults to strict, so behavior is unchanged unless a user explicitly sets `HEADROOM_TLS_STRICT=0`. It clears only the strict flag, never disables verification. - The httpx path uses an explicit context (clean, testable); the urllib3 path needs a monkeypatch because `huggingface_hub` → `requests` builds its context internally and never sees ours. - CHANGELOG.md isn't touched — release-please generates it from the `fix(tls):` commit subject. - I scoped this to the two Python TLS stacks the issue calls out and documented (rather than tried to patch) the separate Rust/ONNX path, since that one resolves through the OS trust store and isn't something this Python toggle can reach.
2026-06-24 20:21:30 +05:30
#### "Basic Constraints of CA cert not marked critical" (Python 3.13+ strict mode)
A **different** failure from the one above. If TLS fails with:
```
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
Basic Constraints of CA cert not marked critical
```
then the corporate CA *is* found and trusted — adding it to a CA bundle changes nothing.
Python 3.13 + OpenSSL 3.x enable `VERIFY_X509_STRICT` by default, which enforces RFC 5280
§4.2.1.9: a CA cert's `basicConstraints` must be marked *critical*. Inspection roots like
Zscaler set `CA:TRUE` without the critical bit, so the chain is rejected.
Set **`HEADROOM_TLS_STRICT=0`** to clear *only* the strict flag from every TLS context
Headroom controls — the proxy's httpx upstream client **and** the urllib3/`huggingface_hub`
path used for model downloads. Chain validation, signature, expiry, and hostname checks all
stay on; this is strictly narrower than disabling verification.
```bash
HEADROOM_TLS_STRICT=0 headroom proxy --port 8787
```
The Rust core's ONNX download (`cdn.pyke.io`) uses a separate TLS stack (rustls / OS trust
store), unaffected by `HEADROOM_TLS_STRICT`. On Windows the corporate root must be in the
**machine** certificate store (browsers already trust it there); or pre-provision ONNX
Runtime with `ORT_STRATEGY=system` + `ORT_LIB_LOCATION=/path/to/onnxruntime` to skip the
download entirely.
## headroom learn
<p align="center">
<img src="headroom_learn.gif" alt="headroom learn in action" width="720">
</p>
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
`headroom learn` — mines failed sessions, writes corrections to `CLAUDE.local.md` (default, gitignored; use `--target CLAUDE.md` for the shared team file) / `AGENTS.md` / `GEMINI.md`.
## Documentation
| Start here | Go deeper |
|-------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| [Quickstart](https://headroom-docs.vercel.app/docs/quickstart) | [Architecture](https://headroom-docs.vercel.app/docs/architecture) |
| [Proxy](https://headroom-docs.vercel.app/docs/proxy) | [How compression works](https://headroom-docs.vercel.app/docs/how-compression-works) |
| [MCP tools](https://headroom-docs.vercel.app/docs/mcp) | [CCR — reversible compression](https://headroom-docs.vercel.app/docs/ccr) |
| [Memory](https://headroom-docs.vercel.app/docs/memory) | [Cache optimization](https://headroom-docs.vercel.app/docs/cache-optimization) |
| [Failure learning](https://headroom-docs.vercel.app/docs/failure-learning) | [Benchmarks](https://headroom-docs.vercel.app/docs/benchmarks) |
| [Configuration](https://headroom-docs.vercel.app/docs/configuration) | [Limitations](https://headroom-docs.vercel.app/docs/limitations) |
fix(cli): harden all CLI surfaces + fix docs accuracy (#1491) ## Summary Full CLI audit + documentation accuracy pass. All 5 commits on this branch: ### CLI Hardening (4 commits) - **Clean errors instead of tracebacks**: corrupt manifests, missing Docker, malformed JSONL, bad `--profile`, invalid env-var values all now raise `click.ClickException` with helpful messages - **Range validation**: ~25 numeric flags across 10 files now use `click.IntRange`/`FloatRange` — `--port 0`, `--hours -1`, `--limit 0` etc. produce clean usage errors instead of silent wrong behavior - **Flag combination warnings**: conflicting combos (`--no-rate-limit` + `--rpm`, `--no-optimize` + `--target-ratio`, `--telemetry` + `--no-telemetry`) emit yellow warnings on stderr - **`memory --db-path` default fixed**: was resolving to `headroom_memory.db` (wrong bare file); now uses project store `./.headroom/memory.db` if present, else `~/.headroom/memory.db` - **`memory list --search` + filters**: `--scope`/`--session`/`--since` were silently ignored when `--search` was also set; now filters are applied to search results - **`learn --verbosity --apply` now works**: the output shaper is off by default (`HEADROOM_OUTPUT_SHAPER`); `--apply` now hot-enables it via `POST /admin/runtime-env` on a running proxy, or prints explicit `export HEADROOM_OUTPUT_SHAPER=1` instructions when no proxy is running - **`perf --hours` overflow**: `1e9` hours no longer raises `OverflowError`; treated as "all data" - **`evals memory --categories` invalid input**: `abc,1,2` now raises `BadParameter` instead of a raw `ValueError` traceback ### Documentation (1 commit, 20 files) Corrected factual errors found by 3 parallel audit agents across root docs, wiki, and the published Fumadocs site: **Critical (caused runtime errors or wrong behavior if followed):** - `simulation.mdx`: `plan.transforms_applied` -> `plan.transforms`; `plan.savings_percent` -> computed from available fields (both raised `AttributeError`) - `shared-context.mdx`: `import { SharedContext } from "headroom"` -> `"headroom-ai"` (5x `ImportError`) - `claude-code-azure-foundry.mdx`: `pip install headroom` -> `pip install headroom-ai` - `api-reference.mdx` + `configuration.mdx`: `from headroom import GoogleProvider` -> `from headroom.providers import GoogleProvider` - `ccr.mdx`: CCR TTL default 300s -> 1800s (30 min) **Fabricated flags removed:** - `wiki/proxy.md` + `wiki/cli.md`: `--no-intelligent-context`, `--no-intelligent-scoring`, `--no-compress-first` (none exist); replaced with real CCR flags - `wiki/configuration.md`: `--no-ccr-responses`, `--no-ccr-expansion` (none exist); replaced with real flags - `wiki/troubleshooting.md`, `wiki/metrics.md`, `docs/troubleshooting.mdx`: `headroom proxy --log-level debug` (flag doesn't exist) **Stale content corrected:** - `llms.txt`: telemetry stated as enabled-by-default (it's opt-in); wrap list had 5 tools (now 11) - `README.md`: compatibility matrix added 5 missing `wrap` targets; `unwrap`, `doctor`, `init`/`install`, savings-analytics now mentioned - `SECURITY.md`: supported version table showed 0.2.x (current: 0.27.x) - `wiki/learn.md`: 5 missing flags added; verbosity shaper-off behavior documented - `wiki/quickstart.md`: "Configuration Reference" linked to `api.md` (wrong) -> `configuration.md` - `CacheAlignerConfig.enabled` default corrected: `True` -> `False` - `opencode.mdx`: `--port` default wrong ("random") -> 8787; `openai` backend removed - `CONTRIBUTING.md`: broken Markdown table cell fixed - `docs/meta.json`: `claude-code-azure-foundry` added to nav (was unreachable orphan page) - `configuration.mdx`: SDK modes vs proxy `--mode` now clearly distinguished ## Test plan - [x] `python -m pytest tests/ -x -q` — 857 passed, 0 failures - [x] 41-combination CLI smoke test (all flag combos across 8 commands) — 0 tracebacks - [x] `ruff check` on all modified Python files — clean - [x] Docs changes are removals/corrections of fabricated or stale content; no new claims introduced
2026-06-27 14:48:43 -07:00
| [Persistent installs](https://headroom-docs.vercel.app/docs/persistent-installs) (`headroom init` / `headroom install apply`) | [Savings analytics](https://headroom-docs.vercel.app/docs/savings) (`headroom savings` / `headroom perf` / `headroom doctor`) |
## Compared to
Headroom runs **locally**, covers **every** content type, works with every major framework, and is **reversible**.
| | Scope | Deploy | Local | Reversible |
|------------------------------------------------------------------------------|------------------------------------------------|------------------------------------|:-----:|:----------:|
| **Headroom** | All context — tools, RAG, logs, files, history | Proxy · library · middleware · MCP | Yes | Yes |
| [RTK](https://github.com/rtk-ai/rtk) | CLI command outputs | CLI wrapper | Yes | No |
| [lean-ctx](https://github.com/yvgude/lean-ctx) | CLI commands, MCP tools, editor rules | CLI wrapper · MCP | Yes | No |
| [Compresr](https://compresr.ai), [Token Co.](https://thetokencompany.ai) | Text sent to their API | Hosted API call | No | No |
| OpenAI Compaction | Conversation history | Provider-native | No | No |
> **Attribution.** Headroom ships with the excellent [RTK](https://github.com/rtk-ai/rtk) binary for shell-output rewriting — `git show --short`, scoped `ls`, summarized installers. Huge thanks to the RTK team; their tool is a first-class part of our stack, and Headroom compresses everything downstream of it. Headroom can also use [lean-ctx](https://github.com/yvgude/lean-ctx) as the selected CLI context tool; set `HEADROOM_CONTEXT_TOOL=lean-ctx` before running `headroom wrap ...`.
## Contributing
```bash
git clone https://github.com/chopratejas/headroom.git && cd headroom
fix: support Copilot Business subscription auth (#641) ## Description Adds a first-party `headroom copilot-auth login` flow for Copilot subscription mode and uses the resulting Copilot OAuth token to perform GitHub's Copilot token exchange before launching the wrapped Copilot CLI. This fixes Business/Enterprise Cloud accounts where a generic GitHub/Copilot token can read Copilot account metadata but is rejected by the Copilot token exchange endpoint. It also avoids treating GitHub.com Enterprise Cloud account URLs such as `github.com/enterprises/acme` as API hostnames. Fixes #635 Related: #488, #610 Builds on #576 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [x] Documentation update - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Adds `headroom copilot-auth login` and `headroom copilot-auth status`. - Stores a Headroom-specific Copilot OAuth token under Headroom's state dir. - Exchanges reusable Copilot OAuth tokens with Copilot Chat-compatible headers before subscription-mode launch. - Carries the resolved Copilot API endpoint into `headroom wrap copilot --subscription`. - Handles GitHub.com Enterprise Cloud URLs without synthesizing invalid `api.github.com/enterprises/...` hosts. - Adds focused unit tests and README guidance for subscription login. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```console ruff check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # All checks passed! ruff format --check headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py # 9 files already formatted python -m py_compile headroom/copilot_auth.py headroom/cli/copilot_auth.py headroom/cli/main.py headroom/cli/__init__.py headroom/cli/wrap.py tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_copilot_subscription_smoke.py uv run --no-project --with pytest --with pytest-asyncio --with click --with rich --with opentelemetry-api --with pydantic --with tiktoken --with 'litellm==1.82.3' --with fastapi --with uvicorn --with 'httpx[http2]' --with openai --with mcp --with magika --with zstandard --with websockets --with onnxruntime --with transformers --with watchdog --with sqlite-vec pytest tests/test_copilot_auth.py tests/test_cli/test_copilot_auth.py tests/test_cli/test_wrap_copilot.py tests/test_cli_proxy_env.py tests/test_copilot_subscription_smoke.py # 127 passed ``` Local note: `uv run pytest ...` against the project currently fails before running tests because `uv.lock` has an unrelated `gitpython` wheel/version mismatch. ## Manual Validation I tested this with an existing GitHub Copilot Business subscription associated with a GitHub.com Enterprise Cloud account. The Enterprise Cloud value I tested was in the form: ```text github.com/enterprises/<enterprise> ``` The tested flow was: ```text headroom copilot-auth login headroom wrap copilot --subscription -- --model gpt-5.4 ``` This validated that Headroom does not treat github.com/enterprises/<enterprise> as a Copilot API hostname. Instead, token exchange uses GitHub.com and Headroom routes subscription-mode traffic to the Copilot API endpoint returned by GitHub for the signed-in account. I did not test this with GitHub Enterprise Server or a custom enterprise domain such as ghe.example.com. No tokens, request IDs, or organization-specific identifiers are included in this PR. ## Real Behavior Proof - Environment: macOS Darwin, Python 3.12.7, local checkout on `codex/copilot-business-auth`. - Exact command / steps: Ran `headroom copilot-auth login`, then launched `headroom wrap copilot --subscription -- --model gpt-5.4` with a GitHub Copilot Business subscription tied to a GitHub.com Enterprise Cloud account. - Observed result: Headroom did not treat `github.com/enterprises/<enterprise>` as a Copilot API hostname; token exchange used GitHub.com and subscription traffic was routed to the Copilot API endpoint returned for the signed-in account. The latest focused Copilot auth/proxy tests pass locally (`127 passed`). - Not tested: GitHub Enterprise Server or custom enterprise domains such as `ghe.example.com`; Windows Credential Manager integration still needs confirmation from someone on Windows. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing targeted unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A ## Additional Notes Acknowledgement: the OAuth/token-exchange behavior was informed by `anomalyco/opencode-copilot-auth` by Aiden Cline. No tokens are printed by the new login/status commands; only a short SHA-256 fingerprint is displayed for troubleshooting. The interactive login is included because the missing piece is not just an Enterprise URL or routing hint. For GitHub.com Enterprise Cloud accounts, URLs like `github.com/enterprises/acme` identify the enterprise account but are not Copilot API hostnames; token exchange still happens through GitHub.com and then returns the account-specific Copilot API endpoint. A command-line enterprise argument can help for true GitHub Enterprise Server/custom-domain deployments, but it cannot produce the Copilot OAuth token class that the token-exchange endpoint accepts. Ideally, Headroom would avoid an extra interactive login and reuse an existing GitHub/Copilot CLI session everywhere. In practice, some reusable-looking tokens can read Copilot account metadata but are rejected by Copilot token exchange, which leaves Business/Enterprise Cloud users with missing model catalogs. The explicit login command is the smallest independent way to obtain and persist the token needed for that exchange without asking users to pass a secret on the command line. --------- Co-authored-by: jbelanger <your-username@users.noreply.github.com>
2026-06-12 21:46:38 -04:00
uv sync --extra dev && uv run pytest
```
Devcontainers in `.devcontainer/` (default + `memory-stack` with Qdrant & Neo4j). See [CONTRIBUTING.md](CONTRIBUTING.md).
## Community
- **[Discord](https://discord.gg/yRmaUNpsPJ)** — questions, feedback, war stories.
feat: switch Kompress default to kompress-v2-base with weight-only int8 ONNX (#799) ## Summary Replaces `chopratejas/kompress-base` with **`chopratejas/kompress-v2-base`** as the default Kompress text-compression model (the fallback for content not handled by structured compressors), using a new **weight-only int8 ONNX** artifact that is fp32-equivalent at 2.2x less memory. ## Why v2 is the same dual-head ModernBERT (token classifier + span CNN), LoRA-trained on the v2 dataset. The HF repo originally shipped PyTorch weights only — pointing Headroom at it naively would have forced the heavy `[ml]` (torch) path on every `[proxy]` install. We exported ONNX artifacts reproducing the v1 loader contract (single `final_scores` output) and published them to the HF repo. ## Eval (labeled dataset_v2 test split, n=500, threshold 0.5) | artifact | size | f1 | must_keep_recall | keep_rate | fp32 agreement | |---|---|---|---|---|---| | fp32 (reference) | 601 MB | 0.9128 | 0.9770 | 0.8100 | 100% | | **int8-wo (default)** | **261 MB** | **0.9130** | **0.9765** | **0.8097** | **99.6%** | | fp16 | 301 MB | 0.9129 | 0.9771 | 0.8099 | 99.9% | | int4-wo | 230 MB | 0.9102 | 0.9825 | 0.8354 ⚠️ | 94.5% | | int8-dynamic | 271 MB | 0.9041 | 0.9868 | 0.8857 ⚠️ | 90.5% | Weight-only int8 (MatMulNBits) keeps activations fp32, avoiding the upward score bias that makes dynamic int8 keep ~7% more tokens (≈40% less compression savings). Quantized candidates were generated and eval-gated by a Modal job in the kompress repo (`modal_jobs/export_onnx_v2.py`) against the labeled test split. ## Changes - Default model id → `chopratejas/kompress-v2-base` - ONNX artifact resolution tries candidates in order (**int8-wo → fp32 → v1 int8**), falling through on download miss **or session-load failure** — onnxruntime builds without the MatMulNBits 8-bit kernel fall back to fp32 instead of losing Kompress - `HEADROOM_KOMPRESS_ONNX_FILENAME` env pins an exact artifact - `scripts/export_kompress_v2_onnx.py`: reproducible fp32 export (loads the merged v2 checkpoint, traces the `final_scores` contract, verifies vs PyTorch) - `.gitignore`: local `onnx/` artifacts dir; allowlist the export script ## Testing - End-to-end: fresh `KompressCompressor().preload()` resolves int8-wo from HF, loads on onnxruntime 1.23 (CPU, no torch), compresses with error/traceback content preserved - fp32 export verified lossless vs PyTorch (max |Δscore| = 0.0, 100% keep agreement) - ruff check + format clean, mypy clean, 63 targeted tests pass
2026-06-09 22:28:40 -08:00
- **[Kompress-v2-base on HuggingFace](https://huggingface.co/chopratejas/kompress-v2-base)** — the model behind our text compression.
## License
fix(ccr): make retrieval TTL configurable (#715) ## Description Make the CCR retrieval store TTL configurable so long-running agent jobs can keep `headroom_retrieve` markers resolvable beyond the previous hard-coded 300-second window. Fixes #714 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Add `HEADROOM_CCR_TTL_SECONDS` for the global CCR `CompressionStore` default TTL, with validation and fallback to 300 seconds. - Expose the effective CCR TTL as `store.default_ttl_seconds` from `/v1/retrieve/stats`. - Distinguish missing vs expired CCR retrieval failures in `/v1/retrieve`, `/v1/retrieve/{hash}`, tool-call handling, and CCR response handling. - Update CCR docs, README wording, and CHANGELOG for the user-facing TTL behavior. - Add regression tests for env-configured TTL, invalid env fallback, explicit TTL precedence, stats exposure, and expired retrieval detail. ## Reproduction Before this change, the proxy-global CCR store always used the default 300-second TTL when callers used `get_compression_store()` without an explicit `default_ttl`. A long-running agent job could receive a `<<ccr:...>>` marker and fail later with a generic not-found/expired response after the fixed 5-minute retention window. The new tests cover this by setting `HEADROOM_CCR_TTL_SECONDS`, creating CCR entries through the same global store used by the proxy, and asserting that stored entries and `/v1/retrieve/stats` use the configured retention. ## Real behavior proof Setup tested: - macOS 15.7.2 - Python 3.13.9 via `uv run --frozen --extra dev --extra proxy` - Local Headroom proxy subprocess: `python -m headroom.proxy.server` - Proxy config: `HEADROOM_TELEMETRY=off`, `HEADROOM_CACHE_ENABLED=false`, `HEADROOM_RATE_LIMIT_ENABLED=false` - Provider/model: no live upstream provider needed; exercised local `/v1/compress` -> `/v1/retrieve` CCR HTTP flow with model `gpt-4o` Exact steps run after the patch: 1. Start a real Headroom proxy process with `HEADROOM_CCR_TTL_SECONDS=7200`. 2. POST a 200-item tool-result payload to `/v1/compress`. 3. Extract the emitted `<<ccr:...>>` marker hash from the compressed messages. 4. GET `/v1/retrieve/stats`. 5. POST `/v1/retrieve` with the marker hash. 6. Repeat with `HEADROOM_CCR_TTL_SECONDS=1`, wait 1.5 seconds, and retrieve the same way to verify explicit expiration reporting. Observed result: ```json { "long_ttl": { "ccr_hash": "b473e632aa47", "retrieve_status": 200, "retrieved_content_has_result_199": true, "stats_default_ttl_seconds": 7200, "stats_entry_count": 1, "ttl_seconds": 7200 }, "short_ttl_expired": { "ccr_hash": "b473e632aa47", "retrieve_detail": "Entry expired (CCR TTL: 1 seconds; age: 2 seconds)", "retrieve_status": 404, "stats_default_ttl_seconds": 1, "stats_entry_count": 1, "ttl_seconds": 1 } } ``` What I did not test: - A live OpenRouter/OpenAI/Anthropic upstream request. - A durable/non-memory CCR backend. - A literal 5+ minute wall-clock wait; the process E2E used `7200` to prove configured retention and `1` second to prove expiration behavior quickly. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ## Test Output ```bash UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_compression_store.py tests/test_proxy_ccr.py tests/test_ccr_response_handler.py tests/test_ccr_response_handler_extra.py # 152 passed, 2 warnings in 12.87s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy pytest tests/test_adapter_hooks.py tests/test_toin_feedback.py tests/test_toin_fixes.py # 55 passed, 13 skipped, 1 warning in 0.53s UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff check . # All checks passed! UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy ruff format --check . # 776 files already formatted UV_SKIP_WHEEL_FILENAME_CHECK=1 uv run --frozen --extra dev --extra proxy mypy headroom # Success: no issues found in 346 source files ``` Existing warnings observed in the targeted tests were unrelated to this change: - AnthropicProvider tiktoken approximation warning in proxy CCR tests. - Deprecated `ToolIntelligenceNetwork.get_recommendation()` warning in existing TOIN assertions. ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) Not applicable. ## Additional Notes No new dependencies. Default behavior remains 300 seconds unless `HEADROOM_CCR_TTL_SECONDS` is set.
2026-06-11 13:20:46 +09:00
Apache 2.0 — see [LICENSE](LICENSE).