CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
All notable changes to Headroom will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Features
- **proxy:** opt-in cost-aware model routing ([#1706](https://github.com/headroomlabs-ai/headroom/issues/1706)). Set `HEADROOM_MODEL_ROUTER_ENABLED=1` and `HEADROOM_MODEL_ROUTES` (a JSON array of ordered rules) to rewrite the upstream model based on estimated input size and tool presence, complementary to content compression, e.g. send small, tool-free requests to a cheaper model. First matching rule wins, and each decision is logged with a reason so routing stays observable. Malformed rules fail open (the rule is skipped, never silently widened). Disabled by default so behavior is unchanged, skipped under `x-headroom-bypass`/passthrough, and currently applied on the Anthropic `/v1/messages` path.
- **install:** `headroom install apply` now accepts `--code-aware/--no-code-aware`, `--intercept-tool-results`, `--protect-tool-results`, and `--bedrock-profile`, mirroring the equivalent flags already on `headroom proxy`. Previously the only way to run a persistent deployment with these settings was to hand-edit `manifest.json` after the fact, which silently reverts on the next `install apply`.
- **install:** `headroom install apply --env KEY=VALUE` (repeatable) passes environment variables into supervised runners (macOS launchd, Linux systemd/cron, Windows services/tasks). These runners previously started with a bare environment and did not inherit the interactive shell's exports — e.g. a custom `HEADROOM_WORKSPACE_DIR` never reached the supervised process, so `headroom install agent run` looked for its manifest in the wrong location and failed outright even though `install apply` itself succeeded. `--env` values are merged into `DeploymentManifest.base_env` last, so they can override auto-derived defaults, and are threaded into the generated `run-headroom.sh`/`ensure-headroom.sh` (and Windows equivalents) as `export`/`$env:` lines before the `exec`.
### Fixed
- **memory:** preserve semantically similar memories after `memory_save`. Cosine similarity now produces a consolidation hint only; it no longer schedules a background deletion, because related memories can describe distinct facts. Supersession remains available through the explicit `memory_update` path with a caller-supplied memory ID.
- **mcp:** reap orphaned `headroom mcp serve` processes when the launching client dies. An MCP stdio server relies on stdin EOF to shut down, but an abrupt client `SIGKILL` leaves the SDK's blocking stdin-reader thread wedged, so `server.run()` never returns; the process is reparented to init/launchd (`ppid == 1`) and lingers, pinning one Python interpreter + tree-sitter grammars per dead session (observed 3+ simultaneously). `run_stdio()` now runs a parent-death watchdog alongside `server.run()` that fires when the captured parent pid changes and `os._exit(0)`s from inside the stdio context manager, bypassing the same wedged teardown ([#2185](https://github.com/headroomlabs-ai/headroom/issues/2185), [#1761](https://github.com/headroomlabs-ai/headroom/issues/1761)).
- **cache/prefix-freeze:** resolve `PrefixCacheTracker`s per conversation lineage within a session id, so concurrent conversations sharing a fallback id no longer thrash one tracker's frozen-prefix state ([#2085](https://github.com/headroomlabs-ai/headroom/issues/2085)). Without an `x-headroom-session-id` header the fallback id hashes `model + system prompt` — identical across a Claude Code session and every one of its parallel subagents (and any set of sessions reusing one system prompt). On the shared tracker their interleaved histories cross-contaminate the freeze state: the forwarded prefix is byte-unstable on nearly every turn and the provider prompt cache is re-written instead of read — reported as ~4.4x cache-creation inflation and a 2.5–3x net cost increase under Claude Code. `SessionTrackerStore.resolve_tracker` now reuses the tracker whose previous request messages are a prefix of the incoming history (client histories are append-only, so a conversation's next request always extends its previous one), starts a fresh lineage when the history diverges or was rewritten (client-side compaction — that provider cache line is gone anyway), and caps lineages per session id (`PrefixFreezeConfig.max_lineages_per_session`, default 32; over-cap conversations share one overflow tracker instead of evicting established lineages, so a fan-out storm past the cap degrades only its own tail — and `0` disables lineage splitting). Matching compares the original client bytes under the same canonical cross-turn equivalence as the cache-stable delta path (`_canonicalize_for_prefix_compare`), so a moved cache breakpoint, string<->block content sugar, or per-turn transport annotations do not read as a rewrite. Separately, the fallback id now hashes only the LEADING run of `role:"system"` messages: agentic clients interleave `<system-reminder>` turns into the history as actual system-role messages (hook output, skills lists, truncation notices), and hashing those rotated the session id mid-conversation — orphaning the prefix tracker and every other session-sticky subsystem (beta headers, CCR/memory registries, the compression cache) each time a reminder landed. Both handler paths now derive the session id and the lineage from the same original client bytes, so a turn-dependent hook rewrite cannot rotate one without the other. The session id itself never changes: session-sticky state keyed on it (beta-header stickiness, CCR and memory-tool registries, the compression cache) is untouched, and a single-conversation session keeps its exact previous behavior (the first lineage lives under the bare id).
- **proxy/bedrock:** wire `PrefixCacheTracker` updates into both Bedrock backend paths (`handle_anthropic_messages`'s non-streaming branch in `anthropic.py`, and `_stream_response_bedrock` in `streaming.py`). `update_from_response()` was previously only called from the direct-Anthropic-API branch; both Bedrock branches returned before ever reaching it, so the tracker's state stayed permanently empty for the life of a session on any `--backend bedrock` deployment: `extract_cache_stable_delta()` always saw no previous turn, and `--mode cache` fell back to full unmodified passthrough on every turn instead of freezing the already-cached prefix and compressing only the new suffix.
- **install:** `install_supervisor`'s macOS branch did an unconditional `launchctl bootout` followed by a bare `bootstrap` with no retry, unlike `start_supervisor`, which already rides out the ~15s EIO (error 5) window launchd exhibits for several seconds after a bootout. This left `install apply`'s own reinstall path (and anything that re-applies a deployment, e.g. a future `headroom doctor --fix`) exposed to a race that previously required manual recovery (bootout + remove the plist + reapply). Extracted the retry loop already used by `start_supervisor` into a shared `_bootstrap_with_retry()` helper, now used by both call sites.
- **proxy/savings:** `SavingsTracker.record_request()` only appended a history point when `tokens_saved > 0` (headroom's own lossy compression). In `--mode cache`, `tokens_saved` is near-always 0 by design, since the frozen prefix is byte-replayed rather than compressed to keep the provider's prompt cache warm. That silently dropped every history point on a cache-mode deployment even when `cache_read_tokens`/`cache_savings_usd` were large, making `headroom-monthly`-style tooling read as a total savings collapse. The guard now fires on `tokens_saved` OR `cache_read_tokens`, and the appended entry carries `cache_read_tokens`/`cache_savings_usd` so downstream consumers can show them; `_normalize_history_entry` defaults both fields to 0/0.0 for legacy entries that predate this change.
- **litellm:** vendor-specific top-level fields on `/v1/chat/completions`, including vLLM's `chat_template_kwargs` for per-request Qwen3 thinking-mode toggles, now reach OpenAI-compatible backends through LiteLLM `extra_body` instead of being dropped by the standard-parameter allowlist ([#2128](https://github.com/headroomlabs-ai/headroom/issues/2128)).
- **cache aligner:** hash the actual frozen Claude Code prefix instead of only system-message text, so `stable_prefix_hash` / `prefix_changed` now surface prompt-cache churn when a cached tool-result block changes without any system-prompt edit ([#2085](https://github.com/headroomlabs-ai/headroom/issues/2085)).
- **proxy image compression:** run native image compression in a spawned subprocess so an OpenCV or KleidiCV crash now fails open to the original image payload instead of taking down the whole proxy process ([#2107](https://github.com/headroomlabs-ai/headroom/issues/2107)).
- **proxy/windows:** support Windows selector-event-loop startup on uvicorn versions older than 0.36. Newer uvicorn accepts `loop="asyncio:SelectorEventLoop"` as a custom loop-factory import path, but older versions treat it as an unknown built-in loop name and raise `KeyError`. Windows now sets `WindowsSelectorEventLoopPolicy` for those older versions instead of passing an unsupported `loop` value ([#1650](https://github.com/headroomlabs-ai/headroom/issues/1650), [#1621](https://github.com/headroomlabs-ai/headroom/issues/1621)).
- **backends/litellm:** preserve `cache_control` on `tool_result` blocks when converting Anthropic messages for the Bedrock Converse path, and complete streaming cache-stats surfacing in `stream_message`. Complements [#1390](https://github.com/headroomlabs-ai/headroom/pull/1390), which preserves `cache_control` on the system prompt and plain text blocks but explicitly leaves `tool_result` out of scope — in agent loops the moving cache breakpoint lands on the tail `tool_result` far more often than on the system prompt, so that gap left most of the caching benefit on the table. Separately, `stream_message` never requested `stream_options.include_usage`, so LiteLLM/Bedrock never returned a usage chunk over SSE and `cache_read_input_tokens`/`cache_creation_input_tokens` always reported 0 downstream even when the prompt cache was genuinely engaged; the terminal `message_delta` now carries the real cache values captured from the trailing usage chunk once the stream completes.
- **shared_context:** `SharedContext.put` no longer evicts an unrelated entry when it merely updates a key that is already cached at capacity — same defect class fixed for `SemanticCache` in [#2094](https://github.com/headroomlabs-ai/headroom/pull/2094).
- **compress:** stop mutating the caller's `CompressConfig`. `compress(config=my_cfg, protect_recent=0, target_ratio=0.2)` used to write those kwargs onto `my_cfg`, so a shared per-agent config was silently rewritten by every request that overrode a single option.
- **paths:** reject `.`, `..`, and NUL as plugin names so `plugin_config_dir` / `plugin_workspace_dir` cannot resolve outside the `plugins/` sandbox. Previously `plugin_config_dir("..")` returned the entire config root and `plugin_workspace_dir("..")` returned the workspace root (savings ledger, memory DB, license cache, logs).
- **backends/litellm:** drop tool names over 64 chars before calling Bedrock Converse (`send_message` and `stream_message`), instead of letting the whole request 401. The Bedrock Converse API hard-rejects any tool name past that length, and Claude Code includes every globally-added claude.ai MCP connector tool in every request, even ones the user hasn't enabled locally, so a single oversized connector name broke every call through this backend. Only the `bedrock` provider filters; other providers forward tool names unfiltered.
- **memory:** annotate `_EMBEDDER_CACHE` as `dict[tuple[str, str, str], Embedder]` to match the 3-element key (backend, model, ollama_base_url). The stale 2-tuple annotation made `mypy headroom` fail on `main`, which broke the `lint` CI job on every open PR.
- **install:** include `orjson` in the `[proxy]` extra so `uv tool install "headroom-ai[all]"` satisfies LiteLLM OpenRouter/provider backends that import it at runtime ([#2056](https://github.com/headroomlabs-ai/headroom/issues/2056)).
- The dashboard's per-request metadata (the `recent_requests` / `request_logs`
tail and the `config` block with upstream URLs) is gated to loopback callers
via `_request_is_loopback`. When Headroom runs in a bridge-network container
(Docker/podman, or Apple Containerization / mocker), a browser on the host
reaches the proxy through the container gateway, so `request.client.host` is
the gateway IP rather than `127.0.0.1` — the sensitive block was stripped and
the "Recent Requests" table rendered empty even though the operator is local.
A peer inside an operator-configured trusted-gateway CIDR
(`HEADROOM_PROXY_TRUSTED_GATEWAY_CIDRS`, already used to sanitize
`X-Forwarded-*`) is now treated as loopback-equivalent, while the loopback
`Host`-header gate is retained as the DNS-rebinding defence. Opt-in and empty
by default, so there is no behavior change unless the gateway CIDR is
allow-listed.
- Non-finite values (`NaN`, `Infinity`) in `proxy_savings.json` or in upstream
cost/token metadata no longer crash the proxy or corrupt the savings
dashboard. `SavingsTracker`'s numeric coercion caught only `TypeError` and
`ValueError`, so `int(float('inf'))` raised an uncaught `OverflowError` while
loading persisted state (`SavingsTracker.__init__` failed and the proxy would
not start), and `float('nan')`/`float('inf')` passed straight through, then
serialized to `NaN`/`Infinity` literals that the dashboard's `JSON.parse`
rejects. `json.loads` accepts those literals, so one bad write poisoned every
later start. Both coercion helpers now also catch `OverflowError` and reject
non-finite floats, failing open to safe defaults.
- `headroom learn` now honors `CLAUDE_CONFIG_DIR`. It resolved the Claude
config directory as `~/.claude` and wrote global memory to
`~/.claude/CLAUDE.md`, so users who relocate their Claude config via that
env var had `learn` scan the wrong directory and detect no projects. The
scanner and memory writer now read/write the configured directory
([#1630](https://github.com/headroomlabs-ai/headroom/issues/1630)).
- `--backend bedrock` now fails fast with an actionable error when temporary
AWS credentials (`AWS_SESSION_TOKEN`) are used but botocore is not installed
(e.g. the slim default Docker image). litellm's session-token auth path
imports botocore, so the missing dependency previously surfaced only at
request time as a misleading `authentication_error: No module named
'botocore'`. The proxy now tells the user to install the `bedrock` extra up
front ([#1551](https://github.com/headroomlabs-ai/headroom/issues/1551)).
- Content detection no longer crashes the proxy on text containing an
orphaned `+++ ` target line with no preceding `--- ` source line (common in
`set -x` xtrace output and partial diffs). The bundled `unidiff` 0.4.0 parser
panics on that input instead of returning an error; the Rust diff detector now
contains the panic and treats the fragment as plain text, so the request is
compressed and forwarded normally instead of returning HTTP 500
([#1547](https://github.com/headroomlabs-ai/headroom/issues/1547)).
- Proactive expansion blocks injected into user turns are now wrapped in
`<headroom_proactive_expansion>` XML tags, giving downstream consumers
(LLMs, loggers, attribution parsers) a machine-readable provenance
boundary and preventing misattribution in multi-agent threads.
- **cli:** the startup banner no longer advertises
`HEADROOM_COMPRESSION_STABLE_AFTER_TURN` and
`HEADROOM_STALE_READ_COMPRESS_AFTER_TURNS` as tuning knobs. Both were read
only to render the `Performance Tuning` banner section and were never wired
into the compression path, so setting them changed the banner but had no
effect on behavior. The banner now surfaces only the embedding sidecar,
which is a real, consumed setting.
- **memory/embedder:** cap CPU thread oversubscription in the local
torch/sentence-transformers embedder. Concurrent encodes previously each
fanned out to ~`os.cpu_count()` BLAS/OpenMP threads, so under load the memory
path starved the asyncio event loop and spiked `/livez` latency to several
seconds. CPU encodes now run on a dedicated, size-limited executor whose
workers each pin their thread pool, bounding total embedding threads to
`HEADROOM_EMBED_CONCURRENCY` × `HEADROOM_EMBED_NUM_THREADS` (defaults
`min(4, cpu)` × 1). The ONNX embedder already capped its threads; this brings
the torch path to parity
([#198](https://github.com/headroomlabs-ai/headroom/issues/198)).
### Changed
* **telemetry:** anonymous usage telemetry is now **opt-in** (off by default) instead of opt-out. Nothing is collected or sent unless you set `HEADROOM_TELEMETRY=on` or pass `--telemetry` to `headroom proxy` / `headroom install apply`. `is_telemetry_enabled()` is fail-closed — only explicit on-values (`on`/`true`/`1`/`yes`/`enable`/`enabled`) enable it; unset, empty, or unrecognized values stay disabled. The existing `--no-telemetry` flag and `HEADROOM_TELEMETRY=off` remain accepted for back-compat, and install manifests now write the `HEADROOM_TELEMETRY` value explicitly so generated deployments are unambiguous.
* **ccr:** `headroom_stats` now labels its formatted proxy output as a rolling/window-scoped session and adds a lifetime savings section from `/stats persistent_savings.lifetime` when present, while keeping existing summary structure and fallback JSON output behavior.
* **docs/ccr:** qualify the current CCR auto-resolution claim by provider. The docs now state that transparent `headroom_retrieve` handling is wired on the Anthropic and OpenAI proxy paths, while native Gemini still lacks that server-side response-handler path and Gemini's OpenAI-compatible endpoint can fail round-2 continuations with `MALFORMED_FUNCTION_CALL` ([#2041](https://github.com/headroomlabs-ai/headroom/issues/2041)).
* **docs/claude:** document that `ENABLE_TOOL_SEARCH=true` is correct for the standalone Claude CLI through Headroom but currently breaks tool-result rendering in Anthropic's VSCode extension webview, and point persistent-install users at the manifest override to set `tool_envs.claude.ENABLE_TOOL_SEARCH` to `"false"` for that target ([#2028](https://github.com/headroomlabs-ai/headroom/issues/2028)).
### Added
* **integrations:** CrewAI tool compression — `wrap_tools_with_headroom()` wraps CrewAI `BaseTool` instances with automatic output compression via `compress_tool_result()`, with per-tool metrics tracking ([#1379](https://github.com/headroomlabs-ai/headroom/issues/1379)).
* **integrations:** AutoGen tool compression — `wrap_tools_with_headroom()` wraps AutoGen `FunctionTool` instances (sync and async) with automatic output compression, including per-tool metrics tracking ([#1379](https://github.com/headroomlabs-ai/headroom/issues/1379)).
### Features
* **grok-build:** add first-class Grok Build support — `headroom wrap grok-build` / `headroom unwrap grok-build`, reversible `~/.grok/config.toml` injection (in-place `base_url` rewrite when `[model.grok-build]` already exists), `GrokRegistrar` MCP install, and install/telemetry wiring ([#1629](https://github.com/headroomlabs-ai/headroom/pull/1629)).
* **wrap:** add `headroom wrap omp` / `headroom unwrap omp` for Oh My Pi — points omp's built-in `anthropic` provider at the local proxy via a marker-fenced `providers.anthropic.baseUrl` override in `~/.omp/agent/models.yml`, snapshotting the pre-wrap file byte-for-byte and restoring it on unwrap. omp resolves its Anthropic chat endpoint from models.yml (`ANTHROPIC_BASE_URL` only feeds its web-search helper), and a same-ID override keeps omp's bundled model catalog and stored credentials ([#1149](https://github.com/headroomlabs-ai/headroom/issues/1149))
* **compress:** expose `frozen_message_count` in library-mode `compress()` via a new `CompressConfig` field (default `0`, unchanged behavior). `read_lifecycle.apply()` already skips stale-Read replacements inside a frozen message prefix, but only the proxy handlers could pass it — `ContentRouter` reads it from transform kwargs and the public API never forwarded it. Library-mode callers that manage their own conversation loop can now stop transforms from rewriting messages already anchored in the provider's prompt cache, which would otherwise convert 0.1x cached prefix reads into full-price cache writes ([#2178](https://github.com/headroomlabs-ai/headroom/pull/2178)).
* **proxy:** report a new-content-relative input savings rate in `/stats`: `tokens.new_input_tokens` (provider-billed non-cache-read input: uncached + cache-write tokens, from response usage) and `tokens.new_input_savings_percent` (savings as a fraction of new input plus the tokens compression removed before they could be billed). The existing whole-request ratios recount the full transcript on every turn, so a 200-turn session counts its history 200x into the denominator and long-running cached sessions (especially 1M-context models, which never compact) dilute toward ~0% regardless of how well compression performs on content newly entering context. Purely additive; existing fields unchanged. Reports 0 when no cache usage data exists (e.g. providers without cache metrics) rather than dividing savings by themselves.
* **transforms:** first-class C# support in `CodeAwareCompressor` via the tree-sitter `csharp` grammar already shipped in the pinned `tree-sitter-language-pack` — no new dependencies ([#1664](https://github.com/headroomlabs-ai/headroom/issues/1664)). Parity with Java/C++/Rust: signatures preserved verbatim, method/constructor/destructor/operator/local-function bodies compressed; block-scoped and file-scoped namespaces, records, structs, interfaces, and enums handled; C#-distinctive auto-detection. Preprocessor conditionals (`#if`…`#endif`) are preserved verbatim as opaque regions (blocks wrapping only `using` directives stay with the imports), `#region` markers no longer swallow the following line during class-member extraction, and top-of-file license banners / `#region License` headers stay on top instead of being relocated below the code. Real-repo runs: 16.1% tokens saved on Newtonsoft.Json (945 files), 37.8% on Polly (797 files), output syntax-valid for 1742/1742 files.
* **proxy:** add provider-only HTTP proxy routing via `--http-proxy` and `HEADROOM_HTTP_PROXY`. Upstream LLM provider calls can now use an HTTP proxy without setting process-wide `HTTP_PROXY`/`HTTPS_PROXY` variables that are inherited by tool executions; proxied provider clients use HTTP/1.1 so HTTPS provider APIs can tunnel through CONNECT.
* **proxy:** add output shaping for OpenAI Responses traffic on `/v1/responses` HTTP requests and Codex WebSocket `response.create` frames, with stable output-savings holdout keys and counted WS token strata for the experiment.
* **stats:** per-bucket output-shaping savings in `/stats-history`. Each `series` bucket (hourly/daily/weekly/monthly) now carries `output_tokens_saved_delta` and `output_savings_usd_delta` alongside the existing compression deltas, sourced from a per-request synthetic-control estimate (`SavingsRecorder.estimate_request_savings`) threaded through `record_request` into the rollup. Lets dashboards chart output-shaping savings over time as a distinct series — previously it existed only as a single global aggregate. Additive and backward-compatible: pre-feature checkpoints default the new fields to 0 ([#1816](https://github.com/headroomlabs-ai/headroom/issues/1816)).
* **observability:** the `headroom.compression.pipeline` span now also carries the OpenTelemetry GenAI semantic-convention attribute `gen_ai.request.model` alongside the existing `headroom.*` attributes, so Headroom's traces group and filter by the standard `gen_ai.*` schema in any OTel-native backend (Grafana, Datadog, etc.). Purely additive; no existing attribute changed. `gen_ai.operation.name`, `gen_ai.provider.name`, and `gen_ai.usage.*` are deliberately deferred (they need per-caller operation threading, reliable upstream-provider resolution, and response-path usage respectively).
* **wrap:** `headroom wrap claude --1m` preserves the 1M context window. Behind a custom `ANTHROPIC_BASE_URL` (the proxy) Claude Code drops the `context-1m` beta header and caps the window at 200k for entitled subscription users; the opt-in flag sets `ANTHROPIC_MODEL=<opus>[1m]` on the launched process so the 1M window activates through Headroom. A model already selected via `ANTHROPIC_MODEL` is preserved (only the `[1m]` suffix is appended) ([#1158](https://github.com/chopratejas/headroom/issues/1158)).
* **learn:** weight loops in `headroom learn`. A new loop detector (`headroom/learn/loops.py`) recognizes repeated tool-call patterns — including RTK re-fetch loops, where RTK's output truncation makes the agent re-run larger-limit variants of a *successful* command — collapses output-limit variants to one signature, measures the wasted tokens, surfaces loops as a highest-priority digest section, and weights loop guardrails above one-off rules by their measured waste. Previously loops had no special weight and a no-failure re-fetch loop was skipped entirely. Adds an RTK-loop eval (`benchmarks/rtk_loop_learn_eval.py`) that reproduces a loop, runs it through Learn, and asserts the generated guardrail ranks first and prevents re-triggering.
* **learn:** write per-project learnings to the personal, gitignored `CLAUDE.local.md` by default instead of the team-shared `CLAUDE.md`, matching Claude Code's memory convention so machine-specific paths and tool-discovery byproducts no longer pollute the shared file. Adds a `--target` flag to override the destination (e.g. `--target CLAUDE.md` to opt back into the shared file, or any custom path), and auto-migrates a stale learned-patterns block out of an existing `CLAUDE.md` into `CLAUDE.local.md` with a warning ([#1072](https://github.com/chopratejas/headroom/issues/1072)).
* **proxy/transforms:** take large cold-start contexts off the synchronous kompress path — the root cause behind the `compression_first_stage` 30s-timeout + leaked-thread → executor-saturation cascade ([#1171](https://github.com/chopratejas/headroom/issues/1171)). A token size-gate inside the ML boundary routes oversized text away from ModernBERT (`HEADROOM_KOMPRESS_MAX_TOKENS`); a cooperative chunk-deadline bounds any kompress run that does proceed (`HEADROOM_COMPRESSION_DEADLINE_MS`); an opt-in off-path mode forwards uncompressed immediately and compresses in a single per-process background drain so the request never blocks on ML (`HEADROOM_BACKGROUND_COMPRESSION`); and a new native `TextCrusher` — a fast deterministic extractive prose compressor in `headroom._core` that reuses the shared BM25 relevance scorer — is the fast alternative to ModernBERT for large plain text (`HEADROOM_TEXT_CRUSHER`). All default off and fail-open. On a SQuAD answer-retention eval (requires the SQuAD dev set) TextCrusher keeps ~94% of buried answers at 30% size vs ~36% for truncate/random, and runs in one O(n) pass -- sub-second where ModernBERT takes minutes (self-contained speed benchmark in `benchmarks/text_crusher_quality_eval.py`).
* **proxy/transforms:** `TextCrusher` now compresses CJK (Chinese/Japanese/Korean) text ([#1171](https://github.com/chopratejas/headroom/issues/1171)). CJK has no spaces or ASCII sentence terminators, so the prior ASCII splitter/tokenizer collapsed a whole CJK paragraph into one segment/one token and passed it through near-uncompressed. CJK-bearing input now takes an ICU (`icu_segmenter`, UAX#29 + dictionary) sentence/word segmentation path with a local BM25 relevance over the ICU tokens; pure-ASCII text is byte-identical to before, and the shared BM25 scorer is untouched. On real CMRC2018 Chinese QA, answer-retention under compression rises from 34% to ~91%; end-to-end aggregate savings on real CJK content rise from 16% to 40%.
* **proxy:** measure and surface rolling and current token throughput metrics (active/wall-clock input, compression, effective forward, and streamed generation) in `headroom perf` CLI and the dashboard ([#959](https://github.com/chopratejas/headroom/issues/959)).
* **vibe:** add Mistral Vibe CLI support with `headroom wrap vibe`.
* **proxy:** per-project savings breakdown on the dashboard for all wrapped agents — Claude Code, Codex, aider, Copilot, and Cursor ([#802](https://github.com/chopratejas/headroom/issues/802)). `headroom wrap claude`/`codex` tag requests with an `X-Headroom-Project` header (launch-directory name); `wrap aider`/`copilot`/`cursor` — whose clients cannot send custom headers — use a `/p/<name>` base-URL prefix the proxy strips. Savings are aggregated per project (persisted, schema v3 with transparent v2 migration), exposed as `savings.per_project` in `/stats` and `projects` in `/stats-history`, and shown in a Per-Project Savings dashboard table.
* **memory:** opt-in Apple-GPU (MPS) embedding offload via `HEADROOM_EMBEDDER_RUNTIME=pytorch_mps`. When set (and Apple MPS is available), the memory embedder runs on the torch sentence-transformers backend on the Apple GPU instead of the default ONNX CPU embedder, freeing the CPU under load. If MPS or the dependencies are unavailable, Headroom logs a warning and uses the existing default embedder selection path (ONNX when available, then the pre-existing local fallback). MPS encode calls are serialized internally (torch-MPS is not thread-safe). Adds the new `[pytorch-mps]` extra (`pip install 'headroom-ai[pytorch-mps]'`). Default behavior is unchanged.
* **proxy:** cross-region Bedrock inference-profile detection — geo-prefixed model IDs (`eu.`/`us.`/`apac.`/`global.`) are now resolved to their canonical vendor, so Anthropic cross-region profiles (e.g. `eu.anthropic.claude-haiku-4-5-20251001-v1:0`) receive live-zone compression instead of being silently skipped ([#999](https://github.com/chopratejas/headroom/pull/999)).
* **proxy:** Converse-body compression on the native Bedrock route — the live-zone dispatcher now recognizes Bedrock Converse content blocks (typeless `{"text": …}`, not only Anthropic `{"type":"text", …}`), so Converse user-message text compresses; `run_anthropic_compression` no longer bails to passthrough when the body lacks an InvokeModel `anthropic_version` envelope, and envelope re-emit stays gated on successful parse ([#999](https://github.com/chopratejas/headroom/pull/999)).
* **docker:** bundle `headroom-proxy` binary in published `runtime` and `runtime-slim` images — closes [#976](https://github.com/chopratejas/headroom/issues/976) ([#999](https://github.com/chopratejas/headroom/pull/999)).
* **transforms:** add opt-in audit-safe mode to `SmartCrusher` — `SmartCrusherConfig(audit_safe=True, protected_patterns=[...], fail_closed_on_protected_loss=True)`. Rows matching a protected pattern are scanned before JSON-array compression and guaranteed to survive the compressed output verbatim afterward (never dropped, never replaced by an opaque `<<ccr:...>>` marker only). Applies on both the `crush_array_json` convenience API and the `_smart_crush_content` path `apply()` uses for real tool-output compression. If a protected row still can't be preserved after the splice-back pass, the crusher fails closed by returning the original uncompressed content (or ships a best-effort result with a warning when `fail_closed_on_protected_loss=False`). Default is `audit_safe=False` — no behavior change for existing callers ([#1705](https://github.com/chopratejas/headroom/issues/1705)).
### Bug Fixes
* **ccr:** normalise a retrieved hash to lowercase so an uppercase echo still hits the store. `parse_tool_call` validated the hash case-insensitively (`hash_key.lower()`) but returned it verbatim, while the compression store keys every entry by a lowercase hash (sha256 hexdigest, and `explicit_hash.lower()` on write) and `retrieve` / `get_entry_status` look the key up as-is. A model that echoed the marker hash in uppercase therefore passed validation but missed the store, failing an otherwise-valid `headroom_retrieve` and losing the original content. `parse_tool_call` now returns the canonical lowercase form.
* **proxy:** run a cold-start fast pass before background-compression deferral so byte-identical freeze doesn't lock sessions to the uncompressed transcript. Since #1850, a session's provider-cached prefix is frozen in whatever form its cold start forwarded; deferring the WHOLE pipeline (`HEADROOM_BACKGROUND_COMPRESSION=1`, frozen=0, ≥50k tokens) therefore cached the raw transcript and forfeited the session's compression savings for its lifetime — including sub-second lossless wins like `read_lifecycle` stale-read drops, observed in the field as sessions permanently stuck at 0 savings. The deferral branch now runs the pipeline synchronously with the new `skip_kompress=True` kwarg (everything except the Kompress ML stage — the only stage that can blow the request budget per #1171) under a bounded fast-pass budget (`HEADROOM_COLD_START_FAST_PASS_TIMEOUT_SECONDS`, default 10s), forwards the pruned form, and defers only Kompress to the background job (tagged `deferred:kompress_background`). Fail-open: on fast-pass timeout/error the request forwards uncompressed exactly as before. Units routed to Kompress under `skip_kompress` take the same fallback as when the model isn't ready.
* **proxy/batch:** preserve sibling tool configs on Google batch requests. When optimizing a Gemini batch item, the handler rebuilt the request's `tools` as a single `[{"functionDeclarations": ...}]` entry, discarding any other entries in the array (`googleSearch`, `codeExecution`, etc.). A batch request that combined function calling with Google Search or code execution therefore reached Google with those siblings stripped, silently disabling them. The handler now replaces only the `functionDeclarations` entry (appending one when the original had none) and keeps every sibling entry intact.
* **savings:** record the pre-compression original as the ledger `before`, not the forwarded count. In `PrometheusMetrics.record_request` the durable savings ledger was written with `tokens_before=input_tokens`, but `input_tokens` there is the optimized (post-compression) count that was forwarded (`emit_request_outcome` passes `outcome.optimized_tokens`). `headroom savings` derives the reported reduction percent as saved / before, so understating `before` by `tokens_saved` inflated it — a real 40% reduction (1000 → 600) was reported as ~67% (400 / 600). The event now records `tokens_before=input_tokens + tokens_saved` (the reconstructed original) and `tokens_after=input_tokens` (the forwarded count); the `saved` and cost figures are unchanged.
* **proxy/gemini:** forward a non-JSON upstream error body with its real status instead of a synthetic 502. In `handle_gemini_generate_content` the token-extraction `except (KeyError, TypeError, AttributeError)` guarding `response.json()` omitted `json.JSONDecodeError` / `ValueError`, so a non-JSON body (an HTML/empty error page from an overloaded Google/Vertex/Copilot frontend, common on 5xx/429) escaped to the outer `except Exception` and was returned as a generic 502 — discarding the real upstream `status_code` and body and defeating the client's retry/backoff. The except now catches the JSON/ValueError family, matching the all-non-text sibling branch, so the true status and body are forwarded verbatim.
* **init/codex:** don't overwrite the user's `hooks.json`. `_ensure_codex_hooks` wrote a fresh payload containing only Headroom's two hooks, wholesale-replacing `~/.codex/hooks.json` — so any user-managed Codex hooks (and other top-level keys) were silently destroyed on `headroom init codex`. It now read-merges: existing entries are preserved, Headroom's are deduped on the `headroom-init-codex` marker and appended, matching `_ensure_claude_hooks` / `_ensure_copilot_hooks`.
* **cli/init:** fail with an actionable error when a target's settings file contains invalid JSON. `_json_file` (used to read-merge-write Claude's `settings.json`, Codex's `hooks.json`, etc.) called `json.loads` unguarded, so a hand-edit typo (e.g. a trailing comma) crashed `headroom init` with a raw `JSONDecodeError` traceback. It now raises a `ClickException` naming the file and the parse error and telling the user to fix it or move it aside, without touching the file (returning `{}` would have made the follow-up write overwrite the user's settings).
* **ccr:** detect `read_lifecycle` stale/superseded markers in the retrieve-tool injector so they stay redeemable. Those markers (`[Read content stale: … Retrieve original: hash=<hash>]`) store the original bytes in the CCR store under a valid hash, but none of `CCRToolInjector`'s patterns matched them — every pattern required the word "compressed" or the `<<ccr:` form. So on a frozen-prefix turn (both `read_lifecycle` and prefix freezing are on by default) the injector reported no compressed content, the `headroom_retrieve` tool was not injected, and the model was handed a marker advertising `Retrieve original: hash=X` with no tool to redeem it — silent data loss for stale reads, where retrieval is the only way to recover the original-at-read-time content (the exact case the #1006 guard exists to prevent). Added a pattern matching the load-bearing `Retrieve original: hash=` phrase, aligning the injector with the sibling `read_maturation` marker that was already (incidentally) detected.
* **install:** don't crash `headroom install status` when the health payload's `config` is a non-dict. The command did `payload.get('config', {}).get('backend', manifest.backend)`, but `dict.get(..., {})` only defaults on a *missing* key — a present-but-non-dict `config` (`null`, a string, a list, e.g. when a different or older service is answering on the port) reached the chained `.get('backend', ...)` and raised `AttributeError`, crashing the command with a raw traceback. The value is now guarded with `isinstance(config, dict)` before the lookup, mirroring `wrap.py`'s `_proxy_health_config`, so it falls back to the manifest's backend.
* **telemetry:** only advance the usage-report baseline after a confirmed 200. `UsageReporter._report_usage` sends usage as a delta against the last snapshot, but it called `_snapshot_metrics()` (and advanced `_last_report_time`) unconditionally after the POST — including when the send returned non-200 or raised. So a report that failed to reach the cloud (which the module is explicitly designed to tolerate) still rebased the baseline, permanently dropping that window's requests/tokens from usage-based billing/quota; the next report started from the advanced baseline and never re-included them. The baseline now advances only on a 200, so a failed send leaves the window intact for the next report to retry.
* **savings:** stop the durable savings ledger from billing free (0-priced) models at the `$3/M` fallback. `estimate_cost_usd` guarded the litellm estimate with `if priced > 0`, so a genuinely free model — where `_estimate_compression_savings_usd` correctly returns `0.0` — was treated as "unpriced" and fell through to the blended fallback rate, writing phantom cost-avoided into the JSONL ledger and surfacing it in `headroom savings`. The ledger now trusts the estimate verbatim for known models (it already falls back internally for models litellm can't price and returns `0.0` for free ones), fixing the same defect at this call site that was already fixed inside the helper.
* **init/codex:** stop `headroom init codex` from deleting per-profile provider settings. `_ensure_codex_provider` removed the root-level `model_provider`/`openai_base_url` (which init owns) with a multiline regex that matched those keys in **every** table, so a user's `[profiles.*]` overrides (e.g. `[profiles.work] model_provider = "azure"`) were silently stripped and those profiles fell through to the injected `"headroom"` default — config corruption. The strip is now scoped to the document root (everything before the first table header), so per-profile overrides are preserved while init still replaces a root-level assignment.
* **proxy:** strip output-only content blocks from request messages before forwarding. Anthropic's server-side refusal-fallback feature (`server-side-fallback-2026-06-01`) emits a `{"type":"fallback","from":{...},"to":{...}}` block inside the assistant response to signal that a refused request was re-served by the fallback model. That block is valid on the *response* path but rejected on the *request* path, so when a client replays the assistant turn the next request 400s (`invalid_request_error: messages.N.content.0: Input tag 'fallback' ...`) and the conversation gets permanently stuck through the proxy. `read_request_json_with_bytes` (Anthropic/OpenAI/Bedrock) and `_read_request_json` (Gemini) now drop such blocks — re-encoding the raw bytes so byte-faithful passthrough cannot leak the pre-strip body, backfilling a benign text block if a turn is emptied, and leaving requests without such blocks byte-identical (no cache churn).
* **wrap/doctor:** make the Claude Remote Control gate warning accurate and stop it firing for users who never had the feature ([#1779](https://github.com/headroomlabs-ai/headroom/issues/1779)). Claude Code 2.1.196 added a client-side check that **deterministically** disables first-party Remote Control (`/remote-control` / `/rc`) whenever `ANTHROPIC_BASE_URL` points at a non-`api.anthropic.com` host — which Headroom always does. The old notice hedged ("may hide the Remote Control menu"); it now states the disable as fact, names the `/rc` command, and detects the installed Claude Code version so the wording is exact (`2.1.196` when known, `2.1.196+` when not). The gate is upstream and RC's control-plane talks to `claude.ai` (not the API host), so Headroom cannot restore it — the warning tells you to run Claude without Headroom for RC sessions. The warning is suppressed for auth modes that never had Remote Control (API-key/PAYG via `ANTHROPIC_API_KEY`/`ANTHROPIC_AUTH_TOKEN`, and Bedrock/Vertex/Foundry cloud IAM) and on Claude Code builds older than 2.1.196 where RC is unaffected by a custom base URL. Both the `headroom wrap claude` launch banner and `headroom doctor` co-report the sibling base-URL gates Headroom *does* restore — on-demand tool loading (#746, automatic) and the 1M context window (#1158, via `--1m`) — and the wrap-side co-report is session-accurate: it says "already restored via --1m" when the flag is in effect and reports tool deferral OFF (not falsely "kept on") when the user chose `--tool-search false`/`ENABLE_TOOL_SEARCH=false`; the `ENABLE_TOOL_SEARCH=...` banner line got the same accuracy fix. `is_custom_anthropic_base_url` now recognizes scheme-less values (`myproxy.local:8080`, `127.0.0.1:8787`) as custom hosts and degrades gracefully on malformed URLs instead of crashing `doctor`. `doctor` resolves the Claude Code version lazily, so runs with no custom base URL never pay the `claude --version` subprocess. No request bytes are touched (cache-safe); this is UX/notice-only.
* **install:** default the docker image to `ghcr.io/headroomlabs-ai/headroom:latest` instead of the dead `ghcr.io/chopratejas/headroom:latest`. After the repo moved to the `headroomlabs-ai` org, GHCR did not redirect the old package, so `headroom install` / `headroom init` and the install scripts pulled a frozen `0.27.0` image while current releases publish to the new path ([#1867](https://github.com/headroomlabs-ai/headroom/issues/1867)).
* **transforms/content-router:** stop a profile-derived `read_protection_window` kwarg from weakening an explicit `--protect-tool-results` guarantee. `ContentRouter.apply()` computes `read_protection_window` from `protect_recent_reads_fraction`, where `0.0` (the sentinel `--protect-tool-results` sets) means "protect all excluded-tool output regardless of conversation depth" per #1374's documented contract — but the method then unconditionally overwrote that window with a `read_protection_window` kwarg whenever one was present. `proxy_pipeline_kwargs()` supplies that kwarg on every request from the active `AgentSavingsProfile.protect_recent` (the default `coding` profile sets `protect_recent=2`), so in practice only the last 2 messages ever kept read-protection and older excluded-tool output silently fell through to lossy compression. The runtime kwarg may now only narrow the window when `protect_recent_reads_fraction > 0`; it can no longer shrink the "protect everything" guarantee set by `--protect-tool-results`.
* **memory:** drop a superseded memory from the search indexes so it stops resurfacing. `supersede` set the old memory's `valid_until` in the store and indexed the new version, but never touched the old entry in the vector/text index. Those indexes keep a cached metadata copy (captured at index time with `valid_until=None`), and default search filters superseded rows off that cached copy — so the superseded, outdated version kept coming back from semantic/text search alongside the new one, injecting contradictory facts into recall. `supersede` now removes the old id from the vector and text indexes (mirroring `delete`); the store still keeps the row for `get_history`.
* **proxy:** don't let a stray `HEADROOM_QDRANT_PORT` crash proxy startup. `ProxyConfig.memory_qdrant_port` used `qdrant_env.qdrant_env_port` as its field `default_factory`, and that function raises `ValueError` on a non-integer or out-of-range value. Because a `default_factory` runs on **every** `ProxyConfig()` construction, an inherited or typo'd `HEADROOM_QDRANT_PORT` crashed the proxy before it served a request — even though memory (and the qdrant backend) are off by default and unrelated to core proxying. The field now resolves the port through a fail-soft wrapper that falls back to the default (6333) with a warning; the strict `qdrant_env_port()` is unchanged for explicit qdrant setup.
* **memory:** size the HNSW `index_batch` resize off the assigned-id high-water mark, not the live entry count. hnswlib never reclaims a slot on `mark_deleted` (used by remove/evict), so its usable capacity is bounded by the number of ids ever assigned (`_next_hnsw_id`). `index_batch` computed `required_capacity = len(self._memory_to_hnsw) + len(new_memories)` — the *live* count — which drops below `_next_hnsw_id` after deletion/eviction churn, so the resize was skipped and `add_items` raised `RuntimeError: number of elements exceeds the specified limit`, crashing the save path on the HNSW backend. It now resizes off `_next_hnsw_id`, matching the single-item `index()` guard.
* **memory:** apply the `turn_id` scope filter even when `agent_id` is absent. In `SQLiteMemoryStore._build_query_conditions` the `turn_id` condition was nested inside the `agent_id` block, so a query filtered by `user_id` + `session_id` + `turn_id` (no `agent_id`) dropped the `turn_id` predicate entirely and returned every memory in the session instead of the single turn — an over-broad result that leaks sibling-turn memories into recall (and makes `count()` wrong for that scope). `agent_id` and `turn_id` are now applied independently.
* **transforms:** stop the lossless `diff` fold from silently dropping lines out of non-diff content. `ContentRouter._lossless_first` tries every `compact_lossless` fold on all content, but the `diff` kind (`diff_strip_index`) is the only one with no exact-inverse check — it removes any line shaped like `index <hex>..<hex>`. Applied to arbitrary text/log/search payloads that happen to contain such a line, that line was deleted with no CCR marker, so it was unrecoverable — a violation of the lossless no-loss contract the method's own docstring promises. The `diff` fold now runs only when the strategy is `DIFF` or the content is diff-shaped (`_looks_like_diff`); genuine diffs still have their `index` bookkeeping folded.
* **proxy:** reject a 0 `rate_limit_requests_per_minute` when rate limiting is enabled, instead of 500-ing every request. The token-bucket wait computation divides by the per-minute rate (`consume_from_bucket`), so a `rate_limit_requests_per_minute` of 0 raised `ZeroDivisionError` on every request that hit the limiter. The CLI already guards this with `IntRange(min=1)`, but the `HEADROOM_PROXY_CONFIG_JSON` / programmatic config paths bypassed it. `ProxyConfig.__post_init__` now validates `rate_limit_requests_per_minute >= 1` when `rate_limit_enabled` (mirroring the existing `retry_max_attempts` check), so a bad value fails fast at construction with a clear message; it stays inert when limiting is disabled.
* **memory:** include the Ollama server URL in the embedder cache key so a second backend can't get an embedder bound to the wrong server. `_create_embedder` cached by `(backend, model)` only, but the Ollama embedder is constructed with `base_url=config.ollama_base_url`. Two configs in the same process that shared a backend and model but pointed at different Ollama servers (e.g. a per-project storage router) collided on one cache slot, so the second silently reused the first's embedder and embedded against the wrong host. The cache key now also includes `ollama_base_url`.
* **tokenizers:** use `o200k_base` for the gpt-4.1 / gpt-4.5 / o4 families in `get_encoding_for_model`. `gpt-4.1*` and `gpt-4.5*` matched the broad `gpt-4` prefix and were encoded with `cl100k_base`, and `o4*` matched no prefix and fell through to the `cl100k_base` default — all three use `o200k_base`, so their token counts were computed with the wrong vocabulary. Added explicit `gpt-4.1`/`gpt-4.5` prefixes ahead of `gpt-4` and an `o4` prefix; `gpt-4` and `gpt-3.5` snapshots still resolve to `cl100k_base`.
* **cache/ccr:** stop counting a successful eviction as a retrieval in the compression feedback learner, which inverted the learning signal. When an entry is evicted without ever being retrieved, `CompressionStore` emits a synthetic `retrieval_type="eviction_success"` event to mark that the compression was sufficient (the LLM never needed the original). `CompressionFeedback.record_retrieval` had no branch for it, so — because the type is not `"full"` — it was counted as a *search retrieval*, inflating the tool's `retrieval_rate`/`search_rate`. `get_compression_hints` reads a high retrieval rate as "compressing too aggressively" and backs off, so a compression that actually worked pushed the learner toward *less* compression (a standalone repro scores one successful eviction as a 100% retrieval rate). The event is now recognized and left out of the retrieval counters; the compression is still counted by `record_compression` at store time, so a never-retrieved entry correctly yields a low retrieval rate. Genuine retrievals are unaffected.
* **proxy/anthropic:** don't launder a non-2xx upstream into HTTP 200 when enterprise security scans the response. On the non-streaming `/v1/messages` path the response-scan branch rebuilt the reply as `httpx.Response(status_code=200)` and returned it without checking the upstream status, so a rate-limit (429), overloaded (529), or other 4xx error whose JSON body was scanned reached the client as an HTTP 200 — the client's retry/backoff never fired and an error looked like success. The branch is now gated on a 200 upstream, matching the sibling CCR/cache/buffered-stream blocks in the same handler; non-2xx responses fall through and keep their real status.
* **learn:** classify timeout and connection tool failures correctly instead of as generic runtime errors. In `classify_error` the generic `RUNTIME_ERROR` pattern (`Traceback|Exception:|Error:`) was checked before the dedicated `TIMEOUT` and `CONNECTION_ERROR` patterns. Because every Python exception repr is `XxxError: ...`, a `TimeoutError: ...` or `ConnectionError: ...` matched the catch-all first and was miscategorized as `RUNTIME_ERROR`, leaving those two categories unreachable for the common colon-repr form (they only fired for tokenless phrasings like `deadline exceeded`). The `TIMEOUT` and `CONNECTION_ERROR` patterns are now checked before the generic catch-all; tokenless generic errors still classify as `RUNTIME_ERROR`.
* **tokenizers:** resolve HuggingFace tokenizer names by the most-specific prefix. `get_tokenizer_name` scanned `MODEL_TO_TOKENIZER` in dict-insertion order and returned the first key the model merely starts with, so a short family key shadowed a more-specific one — `qwen2-7b-instruct` matched `qwen` before `qwen2`/`qwen2-7b` and resolved to the Qwen1 tokenizer (a different vocabulary, hence wrong token counts); `qwen2.5-*` and `deepseek-v2.x` were mis-resolved the same way. It now picks the longest matching prefix, mirroring the order-dependent-prefix guard the sibling tiktoken `get_encoding_for_model` already documents.
* **pricing:** map retired `claude-3-sonnet-20240229` to a Sonnet-tier price instead of Haiku. When LiteLLM's cost DB lacks the retired model, resolution falls through to `MODEL_ALIASES`, which pointed Claude 3 Sonnet (a $3/$15-per-1M model) at `claude-3-haiku-20240307` ($0.25/$1.25) — a different tier that underpriced every cost/savings figure for that model ~12x on both input and output. It now aliases to `claude-sonnet-4-20250514`, the same-price target the other retired-Sonnet aliases already use.
* **cache/semantic:** don't evict an unrelated entry when re-storing a key that is already cached. `SemanticCache.put` ran its at-capacity eviction loop before computing the entry's key, so overwriting a key that was already present (a duplicate or retried store) still evicted the LRU-oldest distinct entry even though an in-place update grows nothing. That silently dropped a live entry and turned a later lookup for it into a false cache miss. The key is now computed first and the eviction loop only runs when the key is genuinely new (mirroring `CompressionCache.store_compressed`, which deletes-then-inserts).
* **learn:** keep `verbosity._ordered_events` in lockstep with `_parse_session` on empty assistant turns. `_parse_session` creates a `_Response` only when an assistant message has content (`words > 0 or out_tok > 0`), but `_ordered_events` consumed a response slot for *every* assistant line. An empty assistant turn (e.g. a pure `tool_use` turn with no usage) therefore shifted the `responses` list out of alignment, so a later human reply was paired with a future-timestamped response, the read gap went negative, and a spurious `fast_skip` was recorded — inflating `fast_skip_rate` and skewing the recommended verbosity level. `_ordered_events` now applies the same `words > 0 or out_tok > 0` guard before consuming a response, matching the filter the user side already mirrors.
* **wrap/claude:** don't raise `UnboundLocalError` in the cleanup `finally` when the proxy fails to start. `claude()` referenced `_wrap_settings_path` in its `finally` block but only assigned it inside the `try`, after `_ensure_proxy` (which raises on port exhaustion or a failed proxy start). An early failure therefore made the `finally` raise `UnboundLocalError` — replacing the real error with a raw traceback and, because the `finally` aborted before `cleanup()`, skipping proxy cleanup and wrap-marker clearing. `_wrap_settings_path` is now bound before the `try` alongside the other cleanup holders (`proxy_holder`, `_saved_base_url`, …), so the `finally` is always safe.
* **wrap/codex:** export the detected custom upstream base URL so Codex actually routes to it. `_inject_codex_provider_config` detects an OpenAI-compatible gateway declared in `~/.codex/config.toml` and writes an `X-Headroom-Base-Url` header mapped to `HEADROOM_CODEX_UPSTREAM_BASE_URL`, and it returns that URL for the caller to export. But `_prepare_codex_wrap_state` discarded the return and `_run_codex_wrap` never set the env var, so Codex emitted no header, the proxy fell back to `api.openai.com`, and the user's gateway key was sent to OpenAI (which rejects it). This restores the wiring a later refactor dropped: `_prepare_codex_wrap_state` now returns the URL and `_run_codex_wrap` exports it into the launch env when set (a user-provided value still wins) (regression of [#1614](https://github.com/chopratejas/headroom/issues/1614)).
* **cache:** normalize embeddings before the semantic dynamic-content similarity check. `SemanticDetector` scored sentences with `np.dot` against exemplar embeddings and compared the result to `semantic_threshold` (a 0-1 cosine value), but `sentence_transformers.encode(..., convert_to_numpy=True)` does not normalize, so the dot product was an unbounded inner product (vector norms ~5-15) rather than a cosine similarity. Nearly every sentence cleared the 0.7 threshold, so the semantic tier flagged almost all text as dynamic and stripped static content, busting the cache it is meant to protect (a standalone repro scores an unrelated sentence, true cosine ~0.1, at a raw dot of ~9). Both `encode` calls now pass `normalize_embeddings=True`, matching the siblings in `prediction/feature_extractor.py` and `memory/adapters/embedders.py`, so the dot product is a true cosine in [-1, 1].
* **subscription:** cap `HeadroomContribution.efficiency_pct` at a real removal ratio so it can't exceed 100%. The numerator used `total_saved()` (which includes `tokens_saved_cache_reads`) while the denominator `raw_without_headroom()` excludes cache reads, so a contribution with large prefix-cache reads and small forwarded input reported impossible values (e.g. `tokens_submitted=100`, `tokens_saved_cache_reads=1000` → `1000.0%` on the dashboard). Cache reads are a provider-side discount on tokens that were still forwarded, not tokens Headroom removed, so the ratio now uses the sibling `compression_saved()` (compression + CLI filtering) as the numerator — bounded by its own denominator. `total_saved()` is unchanged for its other callers.
* **proxy/anthropic:** cache the response under the same messages it was looked up by. The non-streaming `/v1/messages` path snapshots the scalar cache-key fields (system, tools, etc.) once before upstream to avoid post-mutation key drift (#327), but `messages` — the primary key component — was passed live at both `cache.get` and `cache.set`. Between the two, `messages` is reassigned by the enterprise security scan, the `pre_compress` hook, and image compression, so when any of those fired the response was stored under a different key than it was read by: the response cache never hit and accumulated unreachable entries until eviction. The lookup messages are now snapshotted alongside the other key fields and reused verbatim at `cache.set`.
* **tokenizers:** stop `TiktokenCounter.count_messages` from exploding on non-text content blocks. Its multi-part branch handled only `text` and OpenAI `image_url`; every other shape (Anthropic `image`/`tool_result`/`tool_use`, Strands blocks) fell through to `count_text(str(part))`, which json-stringified the base64 payload and tokenized it as text — a 1MB image counted as ~330K phantom tokens (~218x overcount in a standalone repro), corrupting every downstream budgeting/compression decision for multimodal OpenAI-model requests. Unknown block shapes now delegate to the base `_count_content_parts`, which prices images/documents by a bounded estimate (the overcount that helper already exists to prevent).
* **install:** don't let a host env export override the manifest in persistent-docker deployments. `build_runtime_command` emitted the manifest's pinned `--env NAME=VALUE` pairs and then, for every host var matching a passthrough prefix, a bare `--env NAME`. Docker resolves duplicate `--env` last-wins, so a stale host export (e.g. `HEADROOM_BACKEND=anyllm`) that shared a passthrough prefix with a pinned manifest value (`HEADROOM_BACKEND=anthropic`) was appended after it and silently won, diverging the container from its deployment config. The bare passthrough is now skipped for any name the manifest already pins.
* **memory:** honor explicit `store=false` on OpenAI `/v1/responses` requests by skipping Headroom memory-tool injection that depends on stored-response continuations. Memory context injection stays available, and requests no longer get rewritten to `store=true` behind the client's back ([#1944](https://github.com/headroomlabs-ai/headroom/issues/1944)).
* **proxy/batch:** stop corrupting Google `batchGenerateContent` requests whose contents interleave text turns with text-less entries (functionCall/functionResponse/images). The batch handler restored preserved (non-text) entries with the raw-index loop that #836 replaced everywhere else — indexing the shorter `optimized_contents` (text-less entries produce no message) by the original `contents[]` index, which overwrites the wrong entry and drops any preserved entry whose original index is past the optimized length. A request like `[user text, model functionCall, user functionResponse, model text]` was forwarded to Google as two entries: the model's answer overwritten by the functionCall and the functionResponse dropped. The batch handler now uses the shared `_rebuild_gemini_contents` interleaving helper, so all entries survive in order.
* **proxy/gemini:** preserve Gemini code-execution parts (`executableCode` / `codeExecutionResult`) across the compression round-trip. `_has_non_text_parts` only recognized `inlineData`/`fileData`/`functionCall`/`functionResponse`, so a content entry carrying code-execution parts was not marked as preserved. A mixed `text`+`executableCode` entry lost its code payload (only the text survived), and a text-less code-execution entry was treated as a phantom that dropped the entire turn and shifted a neighboring message into the wrong role slot. Both keys are now recognized so those entries are preserved verbatim.
* **cache/ccr:** don't evict a live entry when a duplicate hash is re-stored at capacity. `CompressionStore.store` ran `_evict_if_needed()` before checking whether the key already existed, so re-storing an already-present hash while the store was full evicted the oldest *distinct* entry to "make room" and then merely overwrote the existing key in place — no room was ever needed. The store dropped below `max_entries` and a live, never-retrieved entry was destroyed, so its `<<ccr:...>>` marker (still in the conversation) resolved to a 404. The CCR mirror bridge re-stores the same `explicit_hash` every turn a marker is re-encountered, so this fired routinely. Eviction now runs only for a genuinely new key.
* **tokenizers:** recurse into a native `tool_result` whose content is a list of blocks instead of JSON-serializing it. `_count_content_parts` counted a `tool_result` with list content via `_count_serialized` (json.dumps + sample), so a base64 image nested in a tool result (computer-use / MCP screenshot tools) was priced as text — a ~50-200x overcount (a ~200KB screenshot read as ~70K tokens instead of ~1600). It now recurses into the nested blocks, matching the sibling Strands `toolResult` branch, so the image is priced structurally. The overcount made a single screenshot appear to blow past the model's context window and triggered unnecessary/over-aggressive compression.
* **tokenizers:** price dense scripts (CJK/Kana/Hangul) in the fixed-ratio estimator path. `EstimatingTokenCounter.count_text` applied the CJK correction only on the auto-detect path; its fixed-ratio early return divided by the Latin ratio with no adjustment. The registry builds every provider-calibrated counter with a fixed ratio (Anthropic 3.5, Google 4.0, Cohere 4.0, Moonshot 3.1), and the Anthropic/Gemini proxy handlers count via `get_tokenizer(model).count_messages`, so a CJK-heavy context read as ~40-55% of its true token size — it could fall under the size/backpressure gates and skip compression, and every `x-headroom-tokens-before` metric for CJK traffic was materially wrong. The fixed-ratio path now applies the same dense-script split.
* **ccr:** don't crash `parse_tool_call` on a CCR tool call whose arguments aren't an object. For the OpenAI/`openai_responses` shape the arguments are `json.loads`-decoded and only `JSONDecodeError` was caught, so a model that emitted `arguments='[]'`/`'"abc"'`/`'123'` (decoding to a list/str/number) — or a non-dict Anthropic `input` — reached `input_data.get("hash")` and raised `AttributeError`; a null `arguments` raised an uncaught `TypeError` from `json.loads(None)`. Both are now handled: the decode also catches `TypeError`, and a non-dict `input_data` returns `None` (not a valid CCR call) instead of crashing CCR response processing.
* **proxy/memory:** capture the user's prompt from Anthropic text blocks when building the memory-retrieval query. `extract_memory_query_sources` only recorded `latest_user` when a user message's `content` was a plain string; for the standard Anthropic `/v1/messages` shape (`content=[{"type":"text","text":...}]`, used by Claude Code) it routed into the tool-result extractor and never read the `text` blocks — so the actual question was discarded. On a first turn the embedding query was then empty and memory injection was silently skipped entirely; with history it keyed on stale assistant/tool context instead of the user's ask. The user turn's `text` blocks are now captured.
* **memory/sqlite:** stop `SQLiteMemoryStore.query` from emitting `OFFSET` without a `LIMIT`. The query builder appended `LIMIT` only when `filter.limit is not None` and `OFFSET` independently when `filter.offset > 0`, but SQLite accepts `OFFSET` only as part of a `LIMIT` clause — so a `MemoryFilter(offset=N)` with no limit produced `... OFFSET ?` and crashed with `sqlite3.OperationalError: near "OFFSET": syntax error`. An offset-without-limit now emits SQLite's unbounded `LIMIT -1` so pagination works.
* **mcp/codex:** don't corrupt an unparseable or non-table `config.toml` on register. `CodexRegistrar.register_server` only guarded against clobbering a user-managed entry when `get_server` returned one, but `get_server` returns `None` both for an unparseable TOML file and for an `mcp_servers`/`mcp_servers.<name>` that is present but not a table. In those cases `register_server` fell through to `_write_block`, which blindly appended a `[mcp_servers.<name>]` table — appending into an unparseable file, or creating a duplicate `[mcp_servers.headroom]` key alongside a non-table entry (e.g. `headroom = "..."`), which `tomllib`/codex then reject, destroying a previously-valid config. It now refuses (`FAILED`) and leaves the file untouched, mirroring the claude (#1660) and opencode (#1661) guards.
* **proxy/vertex:** route Vertex `publisher=google` (Gemini) requests to the region matching the request path. `vertex_generate_content`, `vertex_stream_generate_content`, and `vertex_count_tokens` discarded the path's `location` and forwarded to the single fixed host from `_api_target(proxy, "vertex")` (default `us-central1`), instead of the region-aware `_vertex_target_for_location` the sibling Anthropic `rawPredict` route already uses. So a request to `.../locations/europe-west1/publishers/google/...` was sent to a `us-central1` host, which Vertex rejects on the region/host mismatch. The three google routes now derive the host from the request's `location` (operator-pinned upstreams are still honored).
* **proxy/anthropic:** give each Anthropic conversation its own session id. `SessionTrackerStore.compute_session_id` derived its fallback id from `model` + system text harvested only from `role:"system"` entries inside `messages` — but Anthropic carries the system prompt as a top-level `body["system"]` field, so genuine Anthropic requests (which never carry `x-headroom-session-id`) collapsed to `md5(model:[])` and every conversation on the same model shared one `PrefixCacheTracker`. That let session-sticky state cross-contaminate: conversation A's sticky `headroom_retrieve`/memory tools and `anthropic-beta` headers were injected into conversation B, and frozen-prefix/compression-cache state mixed across conversations. The Anthropic handler now folds the top-level `system` into the session-id inputs (prepending a synthetic `role:"system"` message used only to derive the id), giving distinct conversations distinct ids.
* **install/codex:** persistent provider routing is now lifecycle-coupled. `headroom install apply` waits until the runtime is ready before writing managed Codex routing, and stop/remove/recovery paths revert that routing before tearing the proxy down, so Codex Desktop is not left pointed at a dead `127.0.0.1:8787` provider after a failed or stopped deployment ([#2038](https://github.com/headroomlabs-ai/headroom/issues/2038)).
* **cache/semantic:** key entries by the full-context hash, not the trailing query text. `SemanticCache.put` stored each response under `sha256(query)[:16]` where `query` is only the last user message, and the exact-match branch of `get` returned the slot without checking the stored entry's `messages_hash`. Two requests that share a trailing message ("continue", "yes", "run the tests") but differ in earlier context therefore collided on one slot — the second overwrote the first, and the first's hash then resolved to the second's cached response (wrong data served). Entries are now keyed by `messages_hash` when present, and `get` verifies `entry.messages_hash` before returning.
* **wrap/opencode:** `headroom unwrap opencode` now removes the Headroom rtk instruction block from the project and global `AGENTS.md`. `wrap opencode` injects the marker-fenced "prefix shell commands with `rtk`" guidance into both `./AGENTS.md` and `<opencode-home>/AGENTS.md`, but unwrap only restored the config and MCP state — so a plain `opencode` launch kept following the rtk guidance and failed once the managed rtk binary was off PATH. Unwrap now strips the marker-fenced block from both files, mirroring `unwrap codex` (#1421) and `unwrap copilot`.
* **proxy/savings:** stop billing the $3/M fallback rate for genuinely free models. `_estimate_compression_savings_usd` and `_estimate_input_cost_usd` read `input_cost_per_token` from litellm and used `if not input_cost_per_token: raise`, which treats a legitimate `0.0` (a free / local / vendored-at-0 model that litellm does carry) as "price unavailable" and falls back to `DEFAULT_FALLBACK_INPUT_COST_PER_TOKEN` — fabricating dollar savings/cost for a model that costs nothing. Both now use an explicit `is None` check so a present `0.0` flows through as `$0` while a missing key still falls back.
* **proxy/cost:** value prefix-cache savings with the most-used model's price, not the first-recorded one. `build_prefix_cache_stats` scanned `cost_tracker._tokens_sent_by_model` and broke on the *first* provider-matching model with a price — despite the "most-used model" comment — so a Claude Code session (Sonnet for the main loop, Haiku for titles/subagents) priced all of a provider's cache-read savings at whichever model happened to be recorded first. If Haiku ($0.80/M) came before Sonnet ($3/M), the dashboard understated cache savings ~3.75x (and vice-versa). It now picks the provider-matching, priced model with the highest token volume.
* **proxy/openai:** stop overriding an explicit client `stream_options.include_usage` on the streaming chat path. To count tokens from the trailing usage chunk, the handler set `include_usage: True` unconditionally — including flipping an explicit client `false` to `true`. The upstream then appended a usage-only chunk (`choices: []`) the client never requested, and the common `chunk.choices[0].delta` loop raised `IndexError`. The option is now only filled in when the client left the choice open (no `stream_options`, or a dict without `include_usage`); an explicit `true`/`false` is respected.
* **proxy/openai:** stop PRE_SEND from reintroducing `tools: []` after the direct #728 fix. The OpenAI request handler now mirrors the existing `tools or _original_tools is not None` body-write guard during PRE_SEND write-back, so providers that reject empty tool arrays no longer see a tools field when the client omitted it, while explicit client `tools: []` remains preserved ([#1983](https://github.com/headroomlabs-ai/headroom/issues/1983)).
* **proxy/openai:** keep the exact Responses function name `terminal` resident during OpenAI tool-search deferral so cache-mode optimization stops forwarding `terminal.terminal` and triggering the reserved-namespace 400 on Codex Responses ([#1946](https://github.com/headroomlabs-ai/headroom/issues/1946)).
* **proxy/transforms:** startup warmup no longer calls Kompress native preload before the proxy binds its port. Enabled Kompress is deferred to first use, unavailable Kompress stays reported unavailable, and cached-model startup avoids the native ONNX load path that crashed older glibc hosts ([#1908](https://github.com/headroomlabs-ai/headroom/issues/1908)).
* **subscription/copilot:** show a fully-consumed Copilot quota as 100% used instead of unknown. `parse_copilot_quota` read `remaining = raw.get("remaining") or raw.get("quota_remaining")`, so a category reporting `remaining: 0` (quota fully spent) had that legitimate `0` treated as falsy and — with no `quota_remaining` alias in the real payload — collapsed to `None`. `CopilotQuotaCategory.used`/`used_percent` then returned `None`, so the dashboard rendered the exhausted category as `used: -` / 0% (green gauge) rather than `300/300` / 100%. Now uses an explicit `is None` check.
* **proxy/gemini:** thread the savings-profile kwargs into the native Gemini/Vertex compression paths. `handle_gemini_generate_content`, `handle_google_cloudcode_stream`, and `handle_gemini_count_tokens` called `openai_pipeline.apply()` without `proxy_pipeline_kwargs(self.config)`, so `HEADROOM_SAVINGS_PROFILE` and the ProxyConfig knobs (`target_ratio`/`min_tokens_to_compress`/`protect_recent`/`max_items_after_crush`/...) were silently dropped on the Gemini path — those requests compressed with router defaults instead of the configured profile, diverging from the Claude/Codex/Cursor paths. This is the same fix #1534 made for the OpenAI chat path; it now covers Gemini too.
* **wrap:** `headroom wrap claude` no longer installs RTK or lean-ctx by default. Claude context-tool setup is now explicit via `--context-tool`, `--no-context-tool` remains accepted, and other wrap commands keep their current defaults ([#1915](https://github.com/headroomlabs-ai/headroom/issues/1915)).
* **proxy/openai:** thread the savings-profile kwargs into the live `/v1/chat/completions` compression path. The chat handler called `openai_pipeline.apply()` without `proxy_pipeline_kwargs(config)`, so `HEADROOM_SAVINGS_PROFILE=agent-90` (and the individual `compress_user_messages`/`target_ratio`/`min_tokens_to_compress`/... knobs) were silently dropped — OpenAI-compatible clients like OpenCode kept protecting user messages and missed the configured profile. Both the token-mode and non-token chat branches now pass the profile kwargs, matching `handlers/anthropic.py` and the dedicated OpenAI compress endpoint ([#1534](https://github.com/headroomlabs-ai/headroom/issues/1534)).
* **proxy:** forward Codex Desktop `/v1/responses` posts byte-faithfully so they stop returning upstream `400 {"detail":"Bad Request"}`. `handle_openai_responses` decoded the inbound body to inspect it but always re-serialized a canonical body on the way out, and it never stripped the inbound `content-encoding` header — so a `content-encoding: zstd` Codex Desktop request was forwarded as already-decoded JSON still advertising `zstd`, and the upstream ChatGPT Codex endpoint rejected it. The handler now keeps the original decoded bytes and forwards them verbatim whenever nothing (compression or memory injection) mutated the request, and drops the stale `content-encoding` header, mirroring the byte-faithful passthrough the chat and Anthropic paths already use ([#1542](https://github.com/headroomlabs-ai/headroom/issues/1542)).
* **wrap/codex:** `headroom unwrap codex` now removes the Headroom rtk instruction block from the Codex global `AGENTS.md`. `wrap codex` injects it there, but unwrap only restored `config.toml` and MCP state, so a plain `codex` launch kept following the "prefix shell commands with `rtk`" guidance and failed once the managed rtk binary was off PATH. Unwrap now strips the marker-fenced block (preserving the rest of the file), mirroring `unwrap copilot` ([#1421](https://github.com/headroomlabs-ai/headroom/issues/1421)).
* **proxy/auth:** classify real Anthropic OAuth tokens correctly. `classify_auth_mode` matched OAuth on the `sk-ant-oat-` prefix, but real access tokens are `sk-ant-oat01-...` (a version number, no dash after `oat`), so every real subscription/OAuth token fell through to the `sk-` branch and was tagged `PAYG` — enabling aggressive lossy compression, auto `cache_control`, and `prompt_cache_key` injection on subscription-bound requests the classifier is meant to route to the passthrough-prefer path. The prefix is now the dash-less `sk-ant-oat` (still matches the legacy dashed shape). The existing parity tests only passed because they used a synthetic `sk-ant-oat-01-` fixture; a regression test now covers the real `sk-ant-oat01-` format.
* **install:** stop leaking a file descriptor on every `headroom install start`. `start_detached_agent()` opened the agent log file and handed it to `subprocess.Popen` but never closed the parent's copy, so each call leaked one fd (and pinned the log file open against rotation). The parent now closes its copy in a `try/finally` once the child has inherited it — the close also runs if `Popen` raises ([#1554](https://github.com/headroomlabs-ai/headroom/issues/1554)).
* **memory/sync:** stop the Codex AGENTS.md sync adapter from erasing previously-synced memories on every export. `sync_export` hands each adapter only the *delta* (memories the agent lacks), but `CodexAdapter.write_memories` rebuilt its whole managed section from just that delta — so each sync overwrote the section with only the new items, thrashing the file between disjoint subsets and never accumulating. It now merges the delta into the facts already present (deduped), matching the additive contract the ClaudeCode adapter already follows.
* **memory/sync:** stop the Claude Code sync adapter from clobbering distinct memories that share a first line. `write_memories` derived each file name from the first line of the content only (`headroom_{slug}.md`), so two different DB memories whose first lines slugify identically wrote to the same file and the second silently overwrote the first — and because the loser never landed on disk, the next sync re-exported it, ping-ponging the pair forever. When the slug is already taken by a *different* memory (distinct `headroom_id`) the file name is now disambiguated with a content-hash suffix; an update to the same memory still rewrites its slug file in place, so existing file names are unchanged.
* **transforms/code:** stop raising `ValueError` on common language hints and fence tags. `CodeAwareCompressor.compress()` built the language with `CodeLanguage(language.lower())`, which only accepts the exact enum values (`python`/`javascript`/`typescript`/…). A markdown ` ```js ` / ` ```ts ` / ` ```py ` fence tag (or any caller passing an alias) raised `ValueError` — crashing direct callers, and inside the content router the error was swallowed so those blocks silently skipped code-aware compression. A new `coerce_language` helper maps the common aliases to their canonical language and returns `UNKNOWN` (never raises) for unrecognized tags, falling back to content-based detection.
* **cli/proxy:** honor `HEADROOM_MIN_TOKENS=0` / `HEADROOM_MAX_ITEMS=0`. The Click `proxy` command built these with `_get_env_int_optional(name) or 500`/`or 50`, so an explicit `0` — a legitimate value (`min_tokens_to_crush=0` means "crush every item") — was treated as falsy and silently replaced with the default. The `headroom proxy` argparse path already preserved `0` via `_get_env_int`, so the two entry points disagreed. The Click path now uses the same None-checking helper.
* **proxy:** strip the inbound `Content-Encoding`/`Transfer-Encoding` request headers on the Anthropic `/v1/messages` and OpenAI `/v1/chat/completions` paths before forwarding upstream. `read_request_json_with_bytes` already decompresses the inbound body (zstd/gzip/deflate/br), so the bytes forwarded upstream are plain JSON — but these two handlers left the original `content-encoding` header in place, so a client (or an edge proxy like a Cloudflare Worker) that sent a compressed body got its request rejected with upstream HTTP 400 because the provider tried to decompress already-decoded JSON. The `/v1/responses` handler already carried this fix (#1542); it is now applied to the messages and chat paths too.
* **models:** fix the model registry's prefix fallback silently returning the wrong context window. `ModelRegistry.get` accepted any registered name as a `str.startswith` prefix and returned the *first* match, so `gpt-4-32k-0613` resolved to `gpt-4` (8192) instead of `gpt-4-32k` (32768), and unregistered ids like `gpt-4.1`/`gpt-4.5` inherited `gpt-4`'s 8192-token window — making the proxy think a nearly-empty context was almost full and compress far too aggressively. The fallback now requires the registered name to end at a version boundary in the query (so `gpt-4.1` no longer matches `gpt-4`) and picks the longest qualifying name (so `gpt-4-32k-0613` → `gpt-4-32k`).
* **mcp/claude:** stop the file-based MCP registrar from destroying an existing but unparseable Claude config. When the `claude` CLI is unavailable, `_register_via_file` read `~/.claude/.claude.json` via a helper that returns `{}` on `JSONDecodeError`, then rewrote the whole file with only `{"mcpServers": {...}}` — wiping unrelated Claude state (`projects`, `oauthAccount`, session history) if the file was momentarily corrupt or hand-edited. The write path now refuses to overwrite a present-but-invalid config and returns a `FAILED` result with an actionable message; an absent or empty file still registers fresh, and a valid file still merges with all other keys preserved.
* **install:** stop `resolve_targets` from rejecting valid `--providers all`/`auto` installs under provider scope. The provider-scope "unsupported targets" validation ran before the mode dispatch, so `headroom install apply --scope provider --providers all --target cursor` raised `ClickException` even though `all`/`auto` ignore the requested target list entirely (user scope silently ignores the same input). The check now runs only on the manual path that actually consults the requested list.
* **mcp/opencode:** stop the OpenCode MCP registrar from destroying an existing but unparseable `opencode.json`. `_write_entry` read the config via a helper that returns `{}` on `JSONDecodeError`, then rewrote the whole file with only `{"mcp": {...}}` — wiping the user's `theme`/`model`/`provider` and any other MCP servers (OpenCode configs are commonly JSONC / hand-edited). The write path now refuses to overwrite a present-but-invalid config and returns a `FAILED` result; absent/empty files still register fresh and valid files still merge with all other keys preserved. (Same class of fix as the Claude registrar.)
* **proxy:** include the system prompt, tools, and the response-shaping request fields in the SemanticCache key. `_compute_key` hashed only `{model, messages}`, so two non-streaming requests with identical messages but a different top-level `system` prompt, tool set, sampling config, or output-shaping field collided on one key and the second caller was served the first's cached response — generated under different request semantics, in the default config (`cache_enabled` defaults on). The key now folds the request fields that shape generation — `temperature`/`top_p`/`top_k`/`max_tokens`/`stop`, plus OpenAI `tool_choice`/`response_format`/`parallel_tool_calls`/`seed`/`presence_penalty`/`frequency_penalty`/`logit_bias`/`n`/`logprobs`/`top_logprobs`/`reasoning_effort`/`verbosity`/`modalities` and Anthropic `thinking`/`tool_choice`/`output_config` — canonicalizing `system`/`tools` so a moved `cache_control` breakpoint does not fragment it, and the handlers snapshot the fields once at the cache read and reuse them at write so a body mutated by the pipeline cannot diverge the key. Non-streaming path only.
* **learn (verbosity):** `--verbosity --apply --all` now aggregates the savings baseline across every project instead of overwriting it per project (last-project-wins), which previously left the output shaper with a tiny, unrepresentative baseline. The applied verbosity level comes from the project with the most samples ([#1288](https://github.com/headroomlabs-ai/headroom/pull/1288)).
* **proxy/anthropic:** restore token-mode compression on continued Claude Code turns with a frozen prefix and deferred CCR tool injection. Token mode now runs request-side compression even when the client did not pre-register `headroom_retrieve`, relying on the existing marker-triggered injection override to keep emitted CCR markers redeemable ([#1487](https://github.com/headroomlabs-ai/headroom/issues/1487)).
* **proxy:** the dedicated OpenAI handlers (`/v1/chat/completions`, `/v1/responses`) now honor the `x-headroom-base-url` request header, matching the generic passthrough route. Previously only the catch-all passthrough honored it, so OpenAI-compatible gateways (LiteLLM, CPA, self-hosted vLLM, Azure OpenAI) routed correctly for passthrough traffic but the dedicated chat/responses handlers ignored the header and fell back to the default `OPENAI_API_URL`, sending requests (and the user's provider key) to the wrong upstream.
* **subscription:** stop zeroing the 5-hour headroom contribution counters on every poll. The rollover check compared `five_hour.resets_at` with a bare `!=`, but the usage API reports that timestamp with second-level jitter (observed flapping between `01:59:59Z` and `02:00:00Z` on consecutive polls within the same window), so a spurious "5h window rolled over" reset fired every poll interval (~5 min) and the dashboard's per-window savings stuck near 0%. Only a forward jump larger than `_ROLLOVER_MIN_ADVANCE` (1 minute) now counts as a real rollover.
* **wrap:** keep the shared proxy alive when the agent that launched it closes *ungracefully* on Windows. `_start_proxy` spawned the proxy without detaching it, so it stayed in the launcher's console and Job object; closing that terminal window (or `taskkill`/a crash) tree-killed the proxy, bypassing the marker-based reference counting in `_make_cleanup` and breaking every other `headroom wrap` instance routed through the same port. The proxy is now created with `CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB` (with a graceful fallback when the launcher's Job forbids breakaway); POSIX behavior is unchanged. `CREATE_NO_WINDOW` (rather than `DETACHED_PROCESS`) gives the proxy its own *hidden* console: `DETACHED_PROCESS` leaves a console-subsystem exe (`python.exe`) consoleless, so Windows surfaces a visible console window whose close button kills the proxy.
* **transforms/content_router:** stop replacing `role="tool"` output with a lossy-unrecoverable summary on the live compression path (refs [#1307](https://github.com/chopratejas/headroom/issues/1307)). `ContentRouter.apply()` routed OpenAI-style `role="tool"` string messages — `Bash`/`grep`/`ls`/`cat` output — through the ML/word-drop summarizers; when the result carried no CCR retrieve marker (CCR off, ratio >= 0.8, or the size-gate fallback) the original was unrecoverable and the agent acted on a fabricated summary. Tool-role string content is now kept verbatim unless the compressed form is CCR-recoverable. Assistant/user text is unaffected, and structurally-lossless passes (SmartCrusher/Log/Search) still apply. The Anthropic `tool_result` block path is tracked separately.
* **rtk:** stop `rtk` hook registration from spuriously timing out during `headroom wrap`. Output is captured to a temp file instead of pipes, and `stdin` is closed, so a background process forked by `rtk init` can no longer hold the pipe open and block `subprocess.run` past its 10s timeout after the hooks were already registered.
* **ccr:** stop re-compressing `headroom_retrieve` output, which created an infinite retrieval loop, and stop emitting retrieval markers when the `headroom_retrieve` tool is not injected, which silently dropped data ([#1077](https://github.com/chopratejas/headroom/issues/1077), [#1006](https://github.com/chopratejas/headroom/issues/1006)).
* **dashboard:** include RTK stats in the Historical tab; `/stats-history` now attaches live RTK/CLI-filtering stats the same way the Session tab does, so they survive a proxy restart ([#1177](https://github.com/chopratejas/headroom/issues/1177)).
* **opencode:** write Headroom MCP config as a local stdio server instead of a remote `/mcp` URL, keep provider-only installs from adding MCP config, and allow `install apply --target opencode` ([#1380](https://github.com/headroomlabs-ai/headroom/issues/1380)).
* **proxy:** stop discarding a finished compression on very large requests. After the transform pipeline completed, a telemetry-only waste-signal re-parse of the *original* messages ran on the critical path; on huge Claude Code transcripts (~400k tokens) that parse could exceed the Anthropic compression timeout, so the proxy failed open and forwarded the uncompressed request despite "Pipeline complete" logging real savings (`tokens_saved: 0`, `transforms_applied: []`, ~31s latency). Waste-signal detection is now skipped above `MAX_WASTE_SIGNAL_DETECTION_TOKENS` (100k) so the compression result stays on the critical path ([#296](https://github.com/chopratejas/headroom/issues/296)).
* **codex:** retag existing Codex threads when `headroom init` injects the `headroom` provider, so Codex Desktop history stays visible. Codex filters its sidebar/search by the active `model_provider`; the init path set `model_provider = "headroom"` without retagging, so existing native `openai` threads disappeared from the menu (data was never deleted, only hidden). `_ensure_codex_provider` now reconciles thread tags openai→headroom, matching what the install and `wrap` paths already do; `headroom unwrap codex` handles the revert direction ([#961](https://github.com/chopratejas/headroom/issues/961)).
* **install:** stop duplicating the container ENTRYPOINT in the `persistent-docker` runtime command. The published image already runs `headroom proxy` as its ENTRYPOINT, but `build_runtime_command` re-added `headroom proxy` after the image name, so the container ran `headroom proxy headroom proxy --host 0.0.0.0 …` and Click aborted with "Got unexpected extra arguments (headroom proxy)" — the deployment never became ready and rollback left nothing running. The runtime command now appends only the proxy flags ([#833](https://github.com/chopratejas/headroom/issues/833)).
* **proxy:** retry upstream `529 overloaded_error` like a 429 on both the streaming and non-streaming forwarders, honoring `Retry-After`. The streaming path previously surfaced a 529 straight to the client with no retry (interactive sessions saw "Overloaded" immediately), and `_retry_request` retried it only via the generic 5xx path — raising on exhaustion instead of returning the 529 verbatim, and ignoring `Retry-After`. A shared `RETRYABLE_OVERLOAD_STATUSES = {429, 529}` keeps the two forwarders in agreement (extends [#1221](https://github.com/headroomlabs-ai/headroom/issues/1221)).
* **gemini:** run compression off the asyncio event loop. The Gemini handlers (`generateContent`, Cloud Code stream, `countTokens`) ran the CPU-bound compression pipeline (Magika detection plus ML compression) synchronously on the loop, stalling every concurrent request for the duration of each Gemini request's compression. They now offload it via the shared compression executor, matching the existing OpenAI and Anthropic paths.
* **proxy:** run image compression off the asyncio event loop. The Anthropic and OpenAI handlers ran the CPU-bound image compressor (ONNX technique routing plus Pillow resize and OCR) synchronously on the loop, stalling every concurrent request for the duration of each image request's compression. They now offload it via the shared compression executor with a timeout and fail open on error, matching the existing text-compression path.
* **proxy:** queue mid-turn user messages on non-Bedrock streaming path instead of silently dropping them — closes [#902](https://github.com/headroomlabs-ai/headroom/issues/902).
* **proxy:** add `--protect-tool-results` / `HEADROOM_PROTECT_TOOL_RESULTS` to prevent lossy compression of exact-output tool results (e.g. `Bash cat`/`grep` results) — closes [#1307](https://github.com/headroomlabs-ai/headroom/issues/1307).
* **cli:** add `--rpm`/`--tpm` and `HEADROOM_RPM`/`HEADROOM_TPM` to the Click proxy command for rate-limit parity with the legacy CLI -- closes [#1350](https://github.com/headroomlabs-ai/headroom/issues/1350) (Problem 1).
* **proxy:** register `ToolResultInterceptorTransform` in explicit transforms list when `HEADROOM_INTERCEPT_ENABLED` is set — closes [#829](https://github.com/headroomlabs-ai/headroom/issues/829).
* **opencode:** write Headroom MCP config as a local stdio server instead of a remote `/mcp` URL, keep provider-only installs from adding MCP config, and allow `install apply --target opencode` ([#1380](https://github.com/headroomlabs-ai/headroom/issues/1380)).
* **code:** keep Python `from __future__` imports before executable code during AST compression and validate compressed Python with `compile(..., "exec")` so compile-time syntax rules are enforced ([#1233](https://github.com/chopratejas/headroom/issues/1233)).
* **proxy/transforms:** stop the SMART_CRUSHER → Log fallback from collapsing truncated/invalid JSON tool outputs to a single CCR-retrieval marker (99.9% data loss when CCR retrieval isn't configured). The native magika detector classifies content by shape, not parseability, so a mid-stream-truncated JSON payload is tagged `json_array` and routed to SmartCrusher, which returns it unchanged; Kompress passes it through; the LogCompressor then treated the broken JSON as a multi-thousand-line "log" and reduced it to a retrieval marker. A JSON-validity guard now skips the Log fallback for content that fails `json.loads`, so invalid JSON passes through verbatim. Valid JSON arrays still reach the Log fallback (LogCompressor is a no-op on them). The guard also catches `RecursionError` from deeply nested JSON (e.g. `[[[[...]]]]` with 10k+ levels) so the router falls through to a safe strategy instead of crashing ([#1306](https://github.com/chopratejas/headroom/issues/1306)).
* **proxy/transforms:** fix MIXED false-positive on source code. `is_mixed_content` uses regex heuristics that misclassify Python code with dict/list literals (`{`, `[` at line start → `has_json_blocks`) and docstrings/comments (`has_prose`) as mixed content, routing it through `_compress_mixed` which splits it into sections and dispatches each to KOMPRESS — wasting 1–1.4s of latency with 0% compression. When the native magika detector confidently says `SOURCE_CODE` (confidence ≥ 0.8), `_determine_strategy` now trusts it over the regex heuristics. Additionally, when `prefer_code_aware_for_code=False` (the default), source code now uses `PASSTHROUGH` instead of falling back to `KOMPRESS`, which can destroy code semantics (98% compression, 11% fact recall on large blobs). This honours the config's stated intent ("let code pass through unmangled") and reduces latency on code blobs by 23–33×.
* **proxy/transforms:** catch `RecursionError` in `_try_detect_json` so deeply nested JSON arrays (10k+ nesting levels) no longer crash the content detector. The router falls through to a safe strategy (`TEXT` or `PASSTHROUGH`) instead of raising an unhandled exception.
* **proxy:** report real input tokens on the streaming `message_start` event for LiteLLM/Bedrock-backed requests. LiteLLM streaming never surfaces prompt tokens mid-stream, so `message_start.usage.input_tokens` was always `0`; Anthropic clients (e.g. Claude Code) read input-token metrics from that event, underreporting token usage by ~99% in OTel/CloudWatch dashboards. The Bedrock streamer now backfills `input_tokens` with the count Headroom actually sent upstream when the backend leaves it unset, preserving any non-zero value the backend genuinely reports ([#1132](https://github.com/chopratejas/headroom/issues/1132)).
* **proxy:** give buffered Anthropic request paths their own longer read timeout, so long `/v1/messages` turns and Anthropic batch or passthrough reads no longer trip the generic proxy cap while unrelated request timeouts stay unchanged.
* **proxy:** retry upstream 429 rate limits honoring `Retry-After` instead of passing them straight to the client. Both the non-streaming (`_retry_request`) and streaming (`_stream_response`) forwarders returned an upstream 429 verbatim, so a parallel agent fan-out that exceeded the per-minute limit aborted every run; 429s are now retried with backoff (honoring the upstream `Retry-After`, capped at `retry_max_delay_ms`), surfacing only the exhausted 429 to the client ([#1221](https://github.com/chopratejas/headroom/issues/1221)).
* **proxy:** force Responses API `store=true` when Headroom injects memory tools so `previous_response_id` continuations work after memory tool calls from clients that requested `store=false` ([#1103](https://github.com/chopratejas/headroom/pull/1103)).
* **proxy:** build SSL contexts for custom CA bundles so enterprise/private PKI roots work with Python/OpenSSL strict verification.
* **dashboard:** the Proxy $ Saved tile no longer shows a bare `$0.00` when cost pricing is unavailable. Pricing depends on litellm, which pyproject gates off on Python 3.14+, so `/stats` now exposes a top-level `litellm_available` flag and the tile points you to reinstall on Python 3.13 when it is false ([#1296](https://github.com/chopratejas/headroom/pull/1296)).
* **proxy:** the output-savings recorder now reloads the learned baseline before estimating and before each flush, so a baseline written by `headroom learn --verbosity --apply` while the proxy is running takes effect without a restart and the periodic flush no longer overwrites it. Fixes Output Tokens Saved staying at "—" after enabling the shaper ([#1296](https://github.com/chopratejas/headroom/pull/1296)).
* **tokenizers:** bound token-counting of oversized tool-content blobs instead of running `count_text` over the whole serialized string. `count_messages` runs on the proxy request path; serializing is cheap, but `count_text` over a multi-megabyte `tool_result` / `tool_use` string took seconds and could freeze `/health` and in-flight requests. For payloads over ~50KB serialized, `count_text` now runs on an even-spread sample of the string and scales by length; it stays model-accurate, bounded for any blob shape, and biased to under-count. Smaller payloads stay exact.
* **codex:** stop persisting a project-specific `--db` path in the global `headroom_memory` MCP config, so `headroom wrap codex --memory` falls back to the active cwd's `.headroom/memory.db` at runtime while keeping the current project's local bootstrap work scoped correctly ([#1147](https://github.com/chopratejas/headroom/issues/1147)).
* **ccr:** stop emitting Anthropic request-side retrieval markers on frozen-prefix turns when `headroom_retrieve` injection is deferred, so cache-preserving requests forward original content instead of irrecoverable marker-only payloads ([#1006](https://github.com/chopratejas/headroom/issues/1006)).
* **proxy:** route Codex OAuth image generation and edit requests through the ChatGPT Codex image backend, while preserving OpenAI API-key image passthrough ([#1215](https://github.com/chopratejas/headroom/pull/1215)).
* **wrap (codex):** keep RTK guidance in the global Codex `AGENTS.md` instead of modifying the shared project `AGENTS.md` ([#1235](https://github.com/chopratejas/headroom/issues/1235)).
* **subscription:** run the transcript token-window scan off the event loop (`asyncio.to_thread`). The subscription tracker's poll loop scanned every `~/.claude/projects/**/*.jsonl` transcript and `json.loads`'d each line inline on the proxy's single asyncio event loop; on large or long-running sessions this took seconds and froze `/health` and every in-flight proxied request — a periodic "wedge" recurring on the poll interval. The scan now runs in a worker thread so the loop stays responsive.
* **gemini:** resolve future Gemini model capabilities through the shared model registry so token counting and context lookup no longer reject new Gemini families.
* **proxy:** enable SSO credential resolution in the native Bedrock route via the `aws-config` `sso` feature flag, making the credential chain match what `docs/bedrock.md` already documented ([#999](https://github.com/chopratejas/headroom/pull/999)).
* **proxy:** route native Bedrock `/model/{id}/converse` requests to the upstream Converse endpoint instead of the hard-coded `/invoke` action — the non-streaming handler now resolves the action from the inbound path, matching the streaming handler ([#999](https://github.com/chopratejas/headroom/pull/999)).
* **proxy:** preserve byte-faithful `/v1/messages` forwarding when Anthropic tool arrays are already canonical, and only canonicalize-and-mutate tool lists when sorting changes ordering ([#1042](https://github.com/chopratejas/headroom/issues/1042)).
* **ccr:** make retrieval store TTL configurable with `HEADROOM_CCR_TTL_SECONDS`, expose the effective TTL in `/v1/retrieve/stats`, and distinguish expired retrievals from missing hashes.
* **proxy:** make `force_kompress` skip ContentRouter auto-detection during compression and pass savings-profile kwargs through Anthropic batch requests.
* **proxy:** add native Bedrock `/model/{id}/converse-stream` route and forward it through the existing streaming EventStream/SSE pipeline.
* **proxy/kompress:** make pre-upstream backpressure and kompress execution saturation fail-open, so Anthropic requests no longer return 503 during temporary saturation while healthy capacity still compresses and explicit passthrough markers preserve operator visibility ([#1025](https://github.com/headroomlabs-ai/headroom/issues/1025)).
* **wrap (codex):** fix `headroom wrap codex` producing a `config.toml` with duplicate top-level `model_provider` / `openai_base_url` keys (TOML-spec error) when the user had already configured their own provider. The injector now rewrites pre-existing top-level `model_provider` and `openai_base_url` lines in place — the previous value is kept in a `# was: …` trailing comment — instead of unconditionally prepending a duplicate, so `codex` can start against the proxy. The pre-wrap snapshot mechanism continues to byte-for-byte restore the original file on `headroom unwrap codex`.
* **install (macOS):** fix `headroom install restart` / `install start` for launchd `persistent-service` deployments. `stop` `bootout`s the job but `start` only ran `launchctl kickstart`, which cannot recover the un-bootstrapped state `stop`/`restart` leave behind (launchctl error 113), so the proxy was left stopped. `start` now tries `kickstart` (fast path for an already-bootstrapped job) and, on failure, `bootstrap`s the plist fresh — retrying for ~15s to ride out the transient `bootstrap` EIO (error 5) window while launchd releases the label after a `bootout`. `stop` tolerates only the already-absent case (`bootout` ESRCH / error 3) and still raises on any other `bootout` failure ([#1289](https://github.com/headroomlabs-ai/headroom/issues/1289)).
* **wrap:** isolate wrapped proxy subprocess stdout/stderr into `proxy-stdio.log`, so `proxy.log` remains the canonical rotating runtime log and Windows rollover failures from `RotatingFileHandler` are no longer blocked by wrapper stdio handles ([#1184](https://github.com/chopratejas/headroom/issues/1184)).
* **langchain:** fix `HeadroomChatModel.ainvoke()` crashing with `AttributeError: 'AsyncStream' object has no attribute 'model_dump'` when the wrapped model has `streaming=True`. `_agenerate()` now uses a per-call non-streaming copy of the wrapped model instead of mutating shared state across an `await` ([#1285](https://github.com/headroomlabs-ai/headroom/issues/1285)).
* **proxy:** a transient rtk/lean-ctx stat-read failure (timeout, non-zero exit, bad JSON) no longer corrupts the dashboard's CLI-filtering session metrics. Failed reads now return "no data" instead of a synthetic zero payload, and the session baseline is only ever pinned from successful installed-tool reads — previously one hiccup re-pinned the baseline to zero and the next successful read inflated session savings by the tool's entire lifetime, at every proxy boot and `POST /stats/reset`.
* **proxy:** Concurrent large requests no longer 502 on a transient HTTP/2 stream reset. A single upstream `StreamReset` poisons the shared h2 connection and raises `RemoteProtocolError` / `LocalProtocolError` on every in-flight request; those transport errors weren't in the proxy's retry paths, so they collapsed straight to a 502 with no reconnect. The Anthropic non-streaming and streaming retry paths now treat any `httpx.TransportError` (including h2 protocol errors) as retryable before the first client byte, so the bad connection is dropped and the request re-sent on a fresh one ([#1639](https://github.com/headroomlabs-ai/headroom/issues/1639)).
* **install:** `headroom wrap claude` no longer leaves a dead `ANTHROPIC_BASE_URL` in a project's `.claude/settings.local.json` after an unclean exit (`SIGKILL`, OOM, reboot, or terminal/tmux close via `SIGHUP`, which was not caught). `_write_claude_wrap_base_url`/`_restore_claude_wrap_base_url` only removed or restored the entry from the wrap process's own `finally` block, so a crash skipped it and every later bare `claude` invocation in that project inherited the stale proxy URL and hung indefinitely retrying a dead port. A wrap session now stamps a sidecar marker (pid, port, prior value); the next `wrap`, `unwrap`, or `headroom doctor` run detects a marker whose pid is dead or reused and restores the recorded prior value automatically. `claude()` also now catches `SIGHUP` alongside the existing `SIGTERM` handler ([#1768](https://github.com/headroomlabs-ai/headroom/issues/1768)).
* **proxy:** Non-finite values (`NaN`, `Infinity`) in `proxy_savings.json` or in upstream cost/token metadata no longer crash the proxy or corrupt the savings dashboard. `SavingsTracker`'s numeric coercion caught only `TypeError` and `ValueError`, so `int(float('inf'))` raised an uncaught `OverflowError` while loading persisted state (`SavingsTracker.__init__` failed and the proxy would not start), and `float('nan')`/`float('inf')` passed straight through, then serialized to `NaN`/`Infinity` literals that the dashboard's `JSON.parse` rejects. `json.loads` accepts those literals, so one bad write poisoned every later start. Both coercion helpers now also catch `OverflowError` and reject non-finite floats, failing open to safe defaults.
* **learn:** `headroom learn` now honors `CLAUDE_CONFIG_DIR`. It resolved the Claude config directory as `~/.claude` and wrote global memory to `~/.claude/CLAUDE.md`, so users who relocate their Claude config via that env var had `learn` scan the wrong directory and detect no projects. The scanner and memory writer now read/write the configured directory ([#1630](https://github.com/headroomlabs-ai/headroom/issues/1630)).
* **cli:** `--backend bedrock` now fails fast with an actionable error when temporary AWS credentials (`AWS_SESSION_TOKEN`) are used but botocore is not installed (e.g. the slim default Docker image). litellm's session-token auth path imports botocore, so the missing dependency previously surfaced only at request time as a misleading `authentication_error: No module named 'botocore'`. The proxy now tells the user to install the `bedrock` extra up front ([#1551](https://github.com/headroomlabs-ai/headroom/issues/1551)).
* **compression:** Content detection no longer crashes the proxy on text containing an orphaned `+++ ` target line with no preceding `--- ` source line (common in `set -x` xtrace output and partial diffs). The bundled `unidiff` 0.4.0 parser panics on that input instead of returning an error; the Rust diff detector now contains the panic and treats the fragment as plain text, so the request is compressed and forwarded normally instead of returning HTTP 500 ([#1547](https://github.com/headroomlabs-ai/headroom/issues/1547)).
* **proxy:** persist lifetime cache-read savings (tokens + USD) in `proxy_savings.json` (schema v4, additive) so cache-mode savings survive proxy restarts and upgrades. Previously prefix-cache read savings lived only in process memory and every restart reset the dashboard's cache figure to zero; the "Cache Reads (lifetime)" tile now reads the persisted value and the Prefix Cache Impact card renders after a restart with zero traffic, marking session-scoped tiles "no activity since restart".
* **compression:** Proactive expansion blocks injected into user turns are now wrapped in`<headroom_proactive_expansion>` XML tags, giving downstream consumers (LLMs, loggers, attribution parsers) a machine-readable provenance boundary and preventing misattribution in multi-agent threads.
* **cli:** the startup banner no longer advertises `HEADROOM_COMPRESSION_STABLE_AFTER_TURN` and `HEADROOM_STALE_READ_COMPRESS_AFTER_TURNS` as tuning knobs. Both were read only to render the `Performance Tuning` banner section and were never wired into the compression path, so setting them changed the banner but had no effect on behavior. The banner now surfaces only the embedding sidecar, which is a real, consumed setting.
* **memory/embedder:** cap CPU thread oversubscription in the local torch/sentence-transformers embedder. Concurrent encodes previously each fanned out to ~`os.cpu_count()` BLAS/OpenMP threads, so under load the memory path starved the asyncio event loop and spiked `/livez` latency to several seconds. CPU encodes now run on a dedicated, size-limited executor whose workers each pin their thread pool, bounding total embedding threads to `HEADROOM_EMBED_CONCURRENCY` × `HEADROOM_EMBED_NUM_THREADS` (defaults `min(4, cpu)` × 1). The ONNX embedder already capped its threads; this brings the torch path to parity ([#198](https://github.com/headroomlabs-ai/headroom/issues/198)).
* **proxy:** Buffered passthrough routes (e.g. `GET /v1/models`) no longer return an opaque HTTP 502 when an OpenAI-compatible upstream closes a pooled keep-alive connection mid-response (`httpx.RemoteProtocolError` / "incomplete chunked read"). Headroom now retries the request once on a fresh connection — mirroring a direct `curl` — and only returns a clear `upstream_protocol_error` 502 if the upstream is genuinely sending an incomplete response ([#1112](https://github.com/chopratejas/headroom/issues/1112)).
* **ccr:** buffered Anthropic CCR re-streaming now preserves adaptive-thinking response shape, including empty `thinking` blocks, `signature_delta`, `redacted_thinking.data`, verbatim `stop_reason` values such as `refusal`, and `stop_details`.
* **cursor:** `headroom wrap cursor` no longer injects the `rtk` custom-instructions block into `.cursorrules` when rtk's own native Cursor hook registers successfully. rtk supports a real hook for Cursor via `rtk init --agent cursor` (the same mechanism headroom already uses for Claude Code), which rewrites shell commands transparently — the injected `.cursorrules` text duplicated that guidance for no benefit. `wrap cursor` now tries the native hook first and only falls back to injecting `.cursorrules` if hook registration fails (#756).
* **proxy:** The Headroom dashboard no longer tunnels `GET /favicon.ico` to the wrapped upstream provider. No route matched that path, so it fell through to the proxy's catch-all passthrough route and was forwarded to the configured Anthropic/OpenAI/etc. backend — burning a real upstream request (and possibly failing auth) for a browser's automatic favicon fetch on `/dashboard`. A dedicated `/favicon.ico` route now answers with `204 No Content` directly, registered ahead of the passthrough catch-all (#1787).
* **learn:** fix three Windows-specific failures in `headroom learn --verbosity` and CLI-backed analysis ([#1624](https://github.com/headroomlabs-ai/headroom/issues/1624)). `verbosity.py` read transcripts and profiles with the platform-default text codec instead of UTF-8, so non-ASCII content raised a silently-caught `UnicodeDecodeError`, producing `Sessions: 0, human turns: 0` for every project. `_greedy_path_decode` listed a directory's children with `is_dir()` inline in the same expression as `iterdir()`, so a single `PermissionError` on an inaccessible sibling (e.g. the `AppData\Local\Temporary Internet Files` junction present on most Windows profiles) aborted the whole listing and silently mis-decoded any project path that walked through it, causing `--project <path>` to report "No matching project" or resolve the wrong directory. `_call_cli_llm` launched CLI backends via `Popen`/`run`, which use `CreateProcess` on Windows and don't apply the shell's `PATHEXT` extension search, so an npm-installed `.cmd` shim (e.g. `claude`, `codex`) raised `FileNotFoundError` even though it was on `PATH`; a `shutil.which`-based retry now resolves the shim.
* **proxy:** The Anthropic Messages route (`POST /v1/messages`) now honors the `x-headroom-base-url` per-request upstream override. It previously ignored the header and always forwarded to `api.anthropic.com`, so clients that speak the Anthropic Messages wire format while authenticating against a non-Anthropic gateway (e.g. OpenCode Zen) were rejected upstream with `401 invalid x-api-key`. The route now forwards to `<x-headroom-base-url>/v1/messages`, consistent with the OpenAI-compatible and passthrough routes ([#1760](https://github.com/headroomlabs-ai/headroom/issues/1760)).
* **proxy:** the savings store now fsyncs its parent directory after the atomic rename, so the most recent `proxy_savings.json` write survives a power-loss or crash. `_save_locked` fsynced the temp file's contents but never the directory entry the rename created, leaving the rename itself non-durable on POSIX. Best-effort — a no-op on Windows and virtual filesystems where directory fsync is unsupported.
- **code:** fix two `CodeAwareCompressor` AST-reassembly bugs: an exported JS/TS function or class (`export function foo() {`) produced a duplicated `export export` keyword and invalid syntax, because line-based node slicing (used to preserve indentation) pulled in the preceding `export` sibling's text on top of the `export_statement` handler's own prefix reconstruction. Separately, in every supported language, a doc comment immediately above a top-level function, class, or type was detached from its declaration during extraction and re-emitted in a cluster at the end of the compressed output instead of staying attached to what it documents.
- * **proxy:** Buffered upstream responses containing a `server_tool_use` (or any other unrecognized Anthropic content block) no longer turn a fully-generated response into an HTTP 502. `StreamingMixin._response_to_sse` raised `ValueError` on unknown block types after the entire upstream generation had already been buffered, so a slow-but-successful response failed and the client retried the whole multi-minute request. Unknown blocks are now emitted verbatim in `content_block_start` (following the existing redacted_thinking` pattern), so `server_tool_use`, `server_tool_result`, `mcp_tool_use`, and future block types round-trip ([#1806](https://github.com/headroomlabs-ai/headroom/issues/1806)).
## [0.44.0](https://github.com/headroomlabs-ai/headroom/compare/v0.43.1...v0.44.0) (2026-11-09)
### ⚠ BREAKING CHANGES
* **packaging:** keep PyTorch extras out of all ([#4067](https://github.com/headroomlabs-ai/headroom/issues/4067))
### Features
* **pipeline:** say whose request an OutcomeSnapshot is ([#4698](https://github.com/headroomlabs-ai/headroom/issues/4698)) ([a2bcbd1](https://github.com/headroomlabs-ai/headroom/commit/a2bcbd101b1391debfd218ec8c63cb72d2bc240a))
* **providers:** add Hermes agent wrap support ([#934](https://github.com/headroomlabs-ai/headroom/issues/934)) ([7877241](https://github.com/headroomlabs-ai/headroom/commit/7877241d84c93b3ec487e07324245838ddae85cc))
* **proxy/model-router:** add shadow mode (HEADROOM_MODEL_ROUTER_LOG_ONLY) ([#2395](https://github.com/headroomlabs-ai/headroom/issues/2395)) ([861ef95](https://github.com/headroomlabs-ai/headroom/commit/861ef95620c801c2560a2eacc5773a26e131dfd0))
* **proxy:** add lossless /v1/compress mode and detect provider by wire shape ([#4617](https://github.com/headroomlabs-ai/headroom/issues/4617)) ([33f067a](https://github.com/headroomlabs-ai/headroom/commit/33f067a243b2e648730c01ae6b9f20cba879f351))
* **proxy:** expose per-request cost_usd in /stats recent_requests ([#1079](https://github.com/headroomlabs-ai/headroom/issues/1079)) ([#1565](https://github.com/headroomlabs-ai/headroom/issues/1565)) ([84cedbf](https://github.com/headroomlabs-ai/headroom/commit/84cedbf2b4197f09ace9944c50655786dac35b03))
* **proxy:** expose shared Redis store availability in /health and /metrics ([#4578](https://github.com/headroomlabs-ai/headroom/issues/4578)) ([602ca65](https://github.com/headroomlabs-ai/headroom/commit/602ca65126e12d73ef44d4b1b01bbe1fa3b37080))
* **proxy:** give turn hooks one conversation id per client conversation ([#4496](https://github.com/headroomlabs-ai/headroom/issues/4496)) ([94a99ed](https://github.com/headroomlabs-ai/headroom/commit/94a99ed20f6fe110e03d2613e9feec42d9547150))
* **proxy:** report DeepSeek as its own provider in dashboard ([#2565](https://github.com/headroomlabs-ai/headroom/issues/2565)) ([9ad16a7](https://github.com/headroomlabs-ai/headroom/commit/9ad16a77f8b9a7817331aa5e9a9ee04d1e1fc05e))
* **proxy:** show per-request /stats metadata to token-authenticated callers ([#4168](https://github.com/headroomlabs-ai/headroom/issues/4168)) ([9b2dec5](https://github.com/headroomlabs-ai/headroom/commit/9b2dec56f9882a25fb511dc5f480b047845141f9))
* **proxy:** unified multi-upstream routing for Anthropic Cloud and local oMLX ([#4597](https://github.com/headroomlabs-ai/headroom/issues/4597)) ([f896161](https://github.com/headroomlabs-ai/headroom/commit/f896161340893dd8e96502d4c309980bed52d3d1))
* **savings:** carry cumulative actual output_tokens in history checkpoints ([#2921](https://github.com/headroomlabs-ai/headroom/issues/2921)) ([8388ff5](https://github.com/headroomlabs-ai/headroom/commit/8388ff5efd7caf3a827e66bf69449c4a64df05af))
* **wrap:** add `headroom wrap droid` for Factory Droid ([#4143](https://github.com/headroomlabs-ai/headroom/issues/4143)) ([bb8d18a](https://github.com/headroomlabs-ai/headroom/commit/bb8d18a56abb07ca7e811235c86ea6b626eb1f8b))
* **wrap:** make the Serena code-memory MCP opt-in ([#4509](https://github.com/headroomlabs-ai/headroom/issues/4509)) ([2649835](https://github.com/headroomlabs-ai/headroom/commit/2649835a51e6d459ac47e8dcb8591e5bf027715b))
### Bug Fixes
* **asgi:** stop buffering when the client disconnects (GHSA-mc2f-vg4v-2fh4) ([#4701](https://github.com/headroomlabs-ai/headroom/issues/4701)) ([c6d7081](https://github.com/headroomlabs-ai/headroom/commit/c6d708144ce27abeb08c4c57374b373eebe1951e))
* **beacon:** enforce the allowlist below the top-level keys ([#4691](https://github.com/headroomlabs-ai/headroom/issues/4691)) ([456288d](https://github.com/headroomlabs-ai/headroom/commit/456288da0765985ca31eed58dbdaef44ff9aa43a))
* **binaries:** fail closed on HEADROOM_BINARIES_ALLOW_UNVERIFIED=0/false ([#3218](https://github.com/headroomlabs-ai/headroom/issues/3218)) ([da6d973](https://github.com/headroomlabs-ai/headroom/commit/da6d9736cd82074988c7d0a2360b49d9d8b6c0a0))
* **cache:** record TTL observations with relative filenames ([#4711](https://github.com/headroomlabs-ai/headroom/issues/4711)) ([51d9dc5](https://github.com/headroomlabs-ai/headroom/commit/51d9dc59b3dc6b8c386cc2293e78d1334aac0893))
* **cache:** round learned TTL upper bounds up to whole seconds ([#4710](https://github.com/headroomlabs-ai/headroom/issues/4710)) ([13347e3](https://github.com/headroomlabs-ai/headroom/commit/13347e339c4cc88dfa0cfa1deceeb0dae56ee2fc))
* **cache:** save prefix-tracker state when the exit signal arrives ([#4715](https://github.com/headroomlabs-ai/headroom/issues/4715)) ([3ba4223](https://github.com/headroomlabs-ai/headroom/commit/3ba422361e3bce92afd6bb30e3cd817ec3b9cb46))
* **ccr:** lowercase the hash in the streaming feedback recorders ([#2313](https://github.com/headroomlabs-ai/headroom/issues/2313)) ([3912c04](https://github.com/headroomlabs-ai/headroom/commit/3912c0405321c498f854fd0c152ae01abf63bf48))
* **ci:** keep the npm publish token out of install and build steps ([#4690](https://github.com/headroomlabs-ai/headroom/issues/4690)) ([8f6366c](https://github.com/headroomlabs-ai/headroom/commit/8f6366cf66d035fc8e9f390be424bc9bdf6c62e4))
* **cli:** resolve active proxy port for read commands ([#3522](https://github.com/headroomlabs-ai/headroom/issues/3522)) ([02c4e92](https://github.com/headroomlabs-ai/headroom/commit/02c4e922f748cfac5db59303918bb13906031650))
* **content-router:** trust confident HTML detection over mixed-content heuristics ([#3627](https://github.com/headroomlabs-ai/headroom/issues/3627)) ([f50db67](https://github.com/headroomlabs-ai/headroom/commit/f50db67006e2fe3f43b295542b759d90bb73e5a1))
* **dashboard:** lifetime metrics and refresh ([#2374](https://github.com/headroomlabs-ai/headroom/issues/2374)) ([eb9932a](https://github.com/headroomlabs-ai/headroom/commit/eb9932a671c92b19c58949a63ec833869fc1a8e7))
* **doctor:** recognize IPv6 loopback and case-insensitive proxy routing URLs ([#3255](https://github.com/headroomlabs-ai/headroom/issues/3255)) ([2b0315b](https://github.com/headroomlabs-ai/headroom/commit/2b0315b2d4b0d54947050bbdad2de9e89df06378))
* **install:** decode Windows Task Scheduler XML output before parsing ([#3969](https://github.com/headroomlabs-ai/headroom/issues/3969)) ([#4064](https://github.com/headroomlabs-ai/headroom/issues/4064)) ([b78e07d](https://github.com/headroomlabs-ai/headroom/commit/b78e07da7fadeaafdbba16312140d44f812bc181))
* **install:** make install status agree with doctor when the proxy is reachable ([#3072](https://github.com/headroomlabs-ai/headroom/issues/3072)) ([#3141](https://github.com/headroomlabs-ai/headroom/issues/3141)) ([05431b2](https://github.com/headroomlabs-ai/headroom/commit/05431b264f4fc105a302cceed60b5327abc35e10))
* **langchain:** check optional integration availability ([#4042](https://github.com/headroomlabs-ai/headroom/issues/4042)) ([cde584d](https://github.com/headroomlabs-ai/headroom/commit/cde584d7fe6930b8ecf612b705e984b2c6a41527))
* **learn:** harden analyzer JSON parsing against malformed LLM output ([#2471](https://github.com/headroomlabs-ai/headroom/issues/2471)) ([12864fc](https://github.com/headroomlabs-ai/headroom/commit/12864fc8f01a1ca6c58440eccef0dabdd3e595b8))
* **learn:** support opencode v2 session schema in learn scanner ([#4199](https://github.com/headroomlabs-ai/headroom/issues/4199)) ([c05466a](https://github.com/headroomlabs-ai/headroom/commit/c05466a469c848c69a62a5c283c09dcd35d8e9c8))
* **lossless:** fold only pure path listings, never markup ([#4716](https://github.com/headroomlabs-ai/headroom/issues/4716)) ([0ccd559](https://github.com/headroomlabs-ai/headroom/commit/0ccd559db052ea2ec8baef122ac769a146a75518))
* **memory:** gracefully degrade on context lookup and initialization errors ([#3251](https://github.com/headroomlabs-ai/headroom/issues/3251)) ([#4049](https://github.com/headroomlabs-ai/headroom/issues/4049)) ([00d4f44](https://github.com/headroomlabs-ai/headroom/commit/00d4f441d3f1d48c463fea57e6c574c2f3671302))
* **metrics:** cap savings_by_source rows and fold the rest into other ([#4257](https://github.com/headroomlabs-ai/headroom/issues/4257)) ([2038fb2](https://github.com/headroomlabs-ai/headroom/commit/2038fb2a3667d9cba3ff9cb1c4957add06ef5acb))
* **packaging:** keep PyTorch extras out of all ([#4067](https://github.com/headroomlabs-ai/headroom/issues/4067)) ([a890521](https://github.com/headroomlabs-ai/headroom/commit/a8905214d949cdc42b1d76fbc83146f51e0c4f19))
* **proxy:** add --no-ccr-response-handling flag to bypass response buffering ([#3082](https://github.com/headroomlabs-ai/headroom/issues/3082)) ([#3100](https://github.com/headroomlabs-ai/headroom/issues/3100)) ([ce14271](https://github.com/headroomlabs-ai/headroom/commit/ce14271ba8ca66b653fbbb555d50ca20e7a36d3f))
* **proxy:** bound the Bedrock Prometheus model label ([#4694](https://github.com/headroomlabs-ai/headroom/issues/4694)) ([d70a8b7](https://github.com/headroomlabs-ai/headroom/commit/d70a8b76a5bc12b4eae6655e40e60abe19b145d0))
* **proxy:** drop headers named by Connection when forwarding responses ([#4674](https://github.com/headroomlabs-ai/headroom/issues/4674)) ([3871b36](https://github.com/headroomlabs-ai/headroom/commit/3871b3664a03c9dc489be13f245462f2a9fc0b67))
* **proxy:** keep cold-turn reasoning drops sticky so the next warm turn reuses the cached prefix ([#4592](https://github.com/headroomlabs-ai/headroom/issues/4592)) ([3544cf5](https://github.com/headroomlabs-ai/headroom/commit/3544cf5b88a0d0e704f3d3c5eb8a89f7c52d8c13))
* **proxy:** keep the Bedrock credentials provider when startup resolution fails ([#4705](https://github.com/headroomlabs-ai/headroom/issues/4705)) ([5438f00](https://github.com/headroomlabs-ai/headroom/commit/5438f0035d2fd0261b50aac0520b30021dc56fe0))
* **proxy:** refresh Bedrock AWS credentials before they expire ([#4696](https://github.com/headroomlabs-ai/headroom/issues/4696)) ([adc6724](https://github.com/headroomlabs-ai/headroom/commit/adc67249660b4464e8489e21287d9b95d044b095))
* **proxy:** rename leaked_threads metric to timed_out_workers_total ([#3908](https://github.com/headroomlabs-ai/headroom/issues/3908)) ([bd164a2](https://github.com/headroomlabs-ai/headroom/commit/bd164a2c3ba3a2eeb470a0b9503a696dd02b0e9c))
* **proxy:** track response.-prefixed item and content-part events in Responses SSE state ([#4695](https://github.com/headroomlabs-ai/headroom/issues/4695)) ([8f4122f](https://github.com/headroomlabs-ai/headroom/commit/8f4122f4e5ae351703c775e042d2ad705cebc143))
* **router:** compress tool_result blocks in mutable window with trailing messages ([#4717](https://github.com/headroomlabs-ai/headroom/issues/4717)) ([0511bcd](https://github.com/headroomlabs-ai/headroom/commit/0511bcd33186f57d76e508bbec388bb4256cfc68))
* **router:** ignore shell operators inside quoted arguments in read detection ([#4646](https://github.com/headroomlabs-ai/headroom/issues/4646)) ([8cdce17](https://github.com/headroomlabs-ai/headroom/commit/8cdce172ea5b70f9ed5300f089c11f4ca23b8c66))
* **scripts:** skip ci-precheck in the pre-push hook when a push only deletes refs ([#4702](https://github.com/headroomlabs-ai/headroom/issues/4702)) ([cbcf8d8](https://github.com/headroomlabs-ai/headroom/commit/cbcf8d8d9b3c43a93276b46db569fab185ed949d))
* **sdk:** keep Vercel AI SDK tool-result output kinds through compression ([#4670](https://github.com/headroomlabs-ai/headroom/issues/4670)) ([ce42754](https://github.com/headroomlabs-ai/headroom/commit/ce4275491299231bc9d2907833f72f72ea22b8a9))
* **search_compressor:** keep kept rows byte-for-byte and in input order ([#3982](https://github.com/headroomlabs-ai/headroom/issues/3982)) ([a538740](https://github.com/headroomlabs-ai/headroom/commit/a538740ee40a80642bb1092d179171828260696c))
* **smart-crusher:** keep mixed-array dict rows and exact drop count with factor_out_constants ([#4692](https://github.com/headroomlabs-ai/headroom/issues/4692)) ([ced2685](https://github.com/headroomlabs-ai/headroom/commit/ced26852c6d103991e05c5eec1f13103e5ce2755))
* **smart-crusher:** keep the row the question names ([#4713](https://github.com/headroomlabs-ai/headroom/issues/4713)) ([e6e2ebb](https://github.com/headroomlabs-ai/headroom/commit/e6e2ebb6782119e46400a66cef33bb8eb9295484))
* **storage:** return the latest snapshot from JSONLStorage.get ([#4675](https://github.com/headroomlabs-ai/headroom/issues/4675)) ([b25c45b](https://github.com/headroomlabs-ai/headroom/commit/b25c45b08f1cc5ed8fe49671e356711b89800ac1))
* **tabular:** split fixed-width rows on column boundaries, not on double spaces ([#4541](https://github.com/headroomlabs-ai/headroom/issues/4541)) ([b80245e](https://github.com/headroomlabs-ai/headroom/commit/b80245ea73e452f2c14de7a5cd8520f7e7d92c61))
* **tag-protector:** do not treat a slash in an unquoted attribute as self-closing ([#4681](https://github.com/headroomlabs-ai/headroom/issues/4681)) ([d5644cb](https://github.com/headroomlabs-ai/headroom/commit/d5644cbacab79607fe8864d007810aa06c5c68ea))
* **tag-protector:** keep the enclosing tag open after a nested close in marker mode ([#4682](https://github.com/headroomlabs-ai/headroom/issues/4682)) ([385d487](https://github.com/headroomlabs-ai/headroom/commit/385d487f41abd029fb4e2f8346c0cc30dc546bc4))
* **telemetry:** keep install ID stateless ([#3542](https://github.com/headroomlabs-ai/headroom/issues/3542)) ([27bba79](https://github.com/headroomlabs-ai/headroom/commit/27bba79ff2d1800e390ed20820adff971e99ce08))
* **tokenizers:** resolve chatgpt-4o-* aliases to o200k_base ([#4672](https://github.com/headroomlabs-ai/headroom/issues/4672)) ([9648d2d](https://github.com/headroomlabs-ai/headroom/commit/9648d2d867c99eb7e91f81754c5e2877be56feac))
* **tokenizers:** unwrap BatchEncoding in HuggingFaceTokenizer.count_messages ([#2447](https://github.com/headroomlabs-ai/headroom/issues/2447)) ([9eed58f](https://github.com/headroomlabs-ai/headroom/commit/9eed58f84cacc30116c6b6b29cb99eade57e0edf))
* **vertex:** explain Vertex failures in-band, correct the model/region matrix ([#2640](https://github.com/headroomlabs-ai/headroom/issues/2640)) ([0ddaa56](https://github.com/headroomlabs-ai/headroom/commit/0ddaa56c21cdc01c4774391fdcc69e987ecc4e5c))
* **wrap:** route Claude Code's Bedrock mode through Headroom ([#4316](https://github.com/headroomlabs-ai/headroom/issues/4316)) ([aa2093b](https://github.com/headroomlabs-ai/headroom/commit/aa2093b4a08ca1f1bb9c8fb92fe0fc85d9ffe936))
### Dependencies
* bump rusqlite from 0.40.2 to 0.41.1 ([#4658](https://github.com/headroomlabs-ai/headroom/issues/4658)) ([74b7ac2](https://github.com/headroomlabs-ai/headroom/commit/74b7ac23861944f1411d30c5394043ec0505b334))
* bump the cargo-minor-patch group with 3 updates ([#4657](https://github.com/headroomlabs-ai/headroom/issues/4657)) ([c01cf07](https://github.com/headroomlabs-ai/headroom/commit/c01cf07d943d816cfd9d97e6838ed4e38f1ff9a4))
* bump the npm-minor-patch group across 1 directory with 2 updates ([#4650](https://github.com/headroomlabs-ai/headroom/issues/4650)) ([def4ef1](https://github.com/headroomlabs-ai/headroom/commit/def4ef10099514d09188326852138a8b20c26237))
* update click requirement from >=8.3.3 to >=8.5.0 ([#4655](https://github.com/headroomlabs-ai/headroom/issues/4655)) ([ea59ac3](https://github.com/headroomlabs-ai/headroom/commit/ea59ac3eef3a3dc02076e9fe4bb30d572ca9c1a9))
* update sqlite-vec requirement from >=0.1.6 to >=0.1.9 ([#4654](https://github.com/headroomlabs-ai/headroom/issues/4654)) ([de1a1e0](https://github.com/headroomlabs-ai/headroom/commit/de1a1e0f478d1eb9257dd8dd0d4ac87c9e6fc639))
* update tree-sitter requirement from <0.27,>=0.25.2 to >=0.26.0,<0.27 ([#4656](https://github.com/headroomlabs-ai/headroom/issues/4656)) ([910588e](https://github.com/headroomlabs-ai/headroom/commit/910588e6b15ab54c4099d03703e5fa20c8abb757))
## [0.43.1](https://github.com/headroomlabs-ai/headroom/compare/v0.43.0...v0.43.1) (2026-11-05)
### Bug Fixes
* **ccr:** keep the in-memory order queue from evicting re-stored entries ([#4545](https://github.com/headroomlabs-ai/headroom/issues/4545)) ([c6f5bf9](https://github.com/headroomlabs-ai/headroom/commit/c6f5bf9549e9b357e9c2369d4e04bc437f5e180d))
* **memory:** read the relation key the memory_save schema advertises ([#4647](https://github.com/headroomlabs-ai/headroom/issues/4647)) ([7592e68](https://github.com/headroomlabs-ai/headroom/commit/7592e681459f14a2041eb5f524a658cb6ad1dd92))
* **memory:** replace the HNSW vector when a memory is re-indexed ([#4649](https://github.com/headroomlabs-ai/headroom/issues/4649)) ([ee638f9](https://github.com/headroomlabs-ai/headroom/commit/ee638f9532b3788bacd13ed8d26dd0faf0740baf))
* **openclaw:** accept 12-character hashes in headroom_retrieve ([#4640](https://github.com/headroomlabs-ai/headroom/issues/4640)) ([8d3e9e5](https://github.com/headroomlabs-ai/headroom/commit/8d3e9e5ca7cd645eb73084b848edbea5fc796e1a))
* **ort:** avoid implicit runtime discovery from the workspace ([#4570](https://github.com/headroomlabs-ai/headroom/issues/4570)) ([69fbd23](https://github.com/headroomlabs-ai/headroom/commit/69fbd2390d9c8b0fa1f59fb8314bc9b8f01b1a55))
* **proxy:** bound the model-keyed tokenizer, beacon and litellm caches ([#4497](https://github.com/headroomlabs-ai/headroom/issues/4497)) ([e51b806](https://github.com/headroomlabs-ai/headroom/commit/e51b8065a4a2aa3a3c7f266c1cb8d8bde6b568d0))
* **proxy:** use HTTP/1.1 client for ChatGPT streaming and model metadata ([#4006](https://github.com/headroomlabs-ai/headroom/issues/4006)) ([e1becdf](https://github.com/headroomlabs-ai/headroom/commit/e1becdf7329bf4ca03874b9f512ac19837ca29c2))
* **release:** normalize damaged release PR envelopes before detection ([#4664](https://github.com/headroomlabs-ai/headroom/issues/4664)) ([917edc6](https://github.com/headroomlabs-ai/headroom/commit/917edc62230c3c4a8a415e2053da68dab1f003dd))
* **router:** keep tagged blocks out of the lossy size-gate fallback ([#4543](https://github.com/headroomlabs-ai/headroom/issues/4543)) ([f333edf](https://github.com/headroomlabs-ai/headroom/commit/f333edf20f0d7acf5ea67e040c1f58539a0edd4d))
* **router:** log the ONNX fallbacks at info instead of warning ([#4535](https://github.com/headroomlabs-ai/headroom/issues/4535)) ([db30d82](https://github.com/headroomlabs-ai/headroom/commit/db30d82dfffdb3bbe4d60a0e0bfe88640e58470f))
### Dependencies
* bump the npm-minor-patch group across 3 directories with 6 updates ([#4662](https://github.com/headroomlabs-ai/headroom/issues/4662)) ([8f104f8](https://github.com/headroomlabs-ai/headroom/commit/8f104f8e298c85ff0005f2fd4848eea95f32b7c7))
## [0.43.0](https://github.com/headroomlabs-ai/headroom/compare/v0.42.0...v0.43.0) (2026-11-05)
### ⚠ BREAKING CHANGES
* **mcp:** port MCP servers to SDK 2.x ([#4603](https://github.com/headroomlabs-ai/headroom/issues/4603))
### Features
* **ccr:** answer headroom_retrieve on streaming chat completions ([#4631](https://github.com/headroomlabs-ai/headroom/issues/4631)) ([31dcaf4](https://github.com/headroomlabs-ai/headroom/commit/31dcaf41f7fafaebec0838a05ff328da456faef0))
* **mcp:** port MCP servers to SDK 2.x ([#4603](https://github.com/headroomlabs-ai/headroom/issues/4603)) ([ee2252a](https://github.com/headroomlabs-ai/headroom/commit/ee2252a3155c87e948c8893b79af5824eb30e64c))
* **plugins:** headroom skill for Claude Code, Codex, Copilot and skills.sh ([#4533](https://github.com/headroomlabs-ai/headroom/issues/4533)) ([66e1467](https://github.com/headroomlabs-ai/headroom/commit/66e14676827366c2bf8d15e252f8766cb27b1a98))
* **savings:** show the proxy's model-routing savings in headroom savings ([#4304](https://github.com/headroomlabs-ai/headroom/issues/4304)) ([aaab338](https://github.com/headroomlabs-ai/headroom/commit/aaab338b64cb55929de904411db65db126e22ec0))
### Bug Fixes
* [BUG] A timeout in one image compression call resets the shared worker pool and affects concurrent requests ([#4528](https://github.com/headroomlabs-ai/headroom/issues/4528)) ([e9bcfe7](https://github.com/headroomlabs-ai/headroom/commit/e9bcfe73fadf69f0b27b7bc338ea7d2380931054))
* [BUG] DirectMem0Adapter.search_memories calls removed mem0 search API ([#4518](https://github.com/headroomlabs-ai/headroom/issues/4518)) ([d9cee45](https://github.com/headroomlabs-ai/headroom/commit/d9cee452681c79d6f13919e9e651e88a774c0874))
* [BUG] Saved request metrics lose their cache optimization fields ([#4584](https://github.com/headroomlabs-ai/headroom/issues/4584)) ([b4c9bdf](https://github.com/headroomlabs-ai/headroom/commit/b4c9bdf100d97fb038beba95de6d4ad6a8786090))
* [BUG] Volatile SQLite metrics stores lose their schema before the first save ([#4633](https://github.com/headroomlabs-ai/headroom/issues/4633)) ([d8ff0fe](https://github.com/headroomlabs-ai/headroom/commit/d8ff0fe9d2cb2477f6662a90f8fcd7e030a52666))
* Add info about apply to README.md ([#1592](https://github.com/headroomlabs-ai/headroom/issues/1592)) ([4d34680](https://github.com/headroomlabs-ai/headroom/commit/4d34680c34ad379d693820869e77d4a2a6be2cdf))
* **backends/litellm:** keep cache_control on text blocks for Bedrock prompt caching ([#4565](https://github.com/headroomlabs-ai/headroom/issues/4565)) ([23a5bb1](https://github.com/headroomlabs-ai/headroom/commit/23a5bb1c81dc943398f9271f068a02487207f2e7))
* **backends:** forward the standard service_tier param (litellm + anyllm) ([#2468](https://github.com/headroomlabs-ai/headroom/issues/2468)) ([62cc38a](https://github.com/headroomlabs-ai/headroom/commit/62cc38a6b09dbcf723681a0ff56acd02131ad1f1))
* **cache:** build semantic entry before evicting so a failed embedding keeps live entries ([#4581](https://github.com/headroomlabs-ai/headroom/issues/4581)) ([0d4c450](https://github.com/headroomlabs-ai/headroom/commit/0d4c450d774691568b850f0d22ce17e087405281))
* **cache:** count a tool_result with no text as replayable in the frozen prefix ([#4523](https://github.com/headroomlabs-ai/headroom/issues/4523)) ([fba09f6](https://github.com/headroomlabs-ai/headroom/commit/fba09f674c8a9c91b39a563a70ab7727b44d1dbc))
* **cache:** fail closed on SQLite corruption instead of deleting the store online ([#4361](https://github.com/headroomlabs-ai/headroom/issues/4361)) ([9801833](https://github.com/headroomlabs-ai/headroom/commit/98018333f997783487af15efe4d9e631ecd85939))
* **cache:** invalidate configured registry instances on replacement ([#4363](https://github.com/headroomlabs-ai/headroom/issues/4363)) ([1bcdca2](https://github.com/headroomlabs-ai/headroom/commit/1bcdca2d9dd279f49aa4276d523d93c2cfeb5a51))
* **cache:** namespace SemanticCacheLayer by provider, model and metadata ([#4473](https://github.com/headroomlabs-ai/headroom/issues/4473)) ([99cdaaf](https://github.com/headroomlabs-ai/headroom/commit/99cdaaf1c7de2bd81a8e64f198462fd1ceec3a17))
* **cache:** preserve OpenAI tool block metadata on cached replay ([#4334](https://github.com/headroomlabs-ai/headroom/issues/4334)) ([f1035ac](https://github.com/headroomlabs-ai/headroom/commit/f1035ac73788a577fb5495a59eed0fc925d42782))
* **cache:** scope router results to request compression policy ([#4590](https://github.com/headroomlabs-ai/headroom/issues/4590)) ([5d40fe7](https://github.com/headroomlabs-ai/headroom/commit/5d40fe76471b12ffe2a5c81309d9df617ca60b41))
* **ccr:** buffer a stream only for a marker new this turn ([#4607](https://github.com/headroomlabs-ai/headroom/issues/4607)) ([946a70c](https://github.com/headroomlabs-ai/headroom/commit/946a70cfcbdc522f940b01f0aeb2b7a214f54cb5))
* **ccr:** keep proactive expansion out of the cached prefix ([#4300](https://github.com/headroomlabs-ai/headroom/issues/4300)) ([b1f340e](https://github.com/headroomlabs-ai/headroom/commit/b1f340e0b35d4659d7ebc993d9dcc08057da93e9))
* **cli:** document that code-aware compression is enabled by default ([#4616](https://github.com/headroomlabs-ai/headroom/issues/4616)) ([affd17c](https://github.com/headroomlabs-ai/headroom/commit/affd17c5fde174ad78287eef1696251e18363722))
* **client:** close upstream responses when wrapped streams are closed ([#4482](https://github.com/headroomlabs-ai/headroom/issues/4482)) ([3d8dcf4](https://github.com/headroomlabs-ai/headroom/commit/3d8dcf476c148f633e66eb98c478095adfd9354b))
* **client:** honor configured cache optimizer enablement ([#4501](https://github.com/headroomlabs-ai/headroom/issues/4501)) ([d4c0810](https://github.com/headroomlabs-ai/headroom/commit/d4c0810ea3ebdd7e49e5d29f4e0dfd2da1511b02))
* **client:** preserve Anthropic create stream flags ([#4500](https://github.com/headroomlabs-ai/headroom/issues/4500)) ([3910caa](https://github.com/headroomlabs-ai/headroom/commit/3910caabd68311ae99d5659aa2d470eb2c15ea0e))
* **codex:** accept multi-line inline tables in Codex config.toml ([#4436](https://github.com/headroomlabs-ai/headroom/issues/4436)) ([4a851ed](https://github.com/headroomlabs-ai/headroom/commit/4a851ed25469a51de00ccd00d14d0a6ab62a0866))
* **compaction:** reject negative dictionary indices and non-array legends in expand_compacted ([#4470](https://github.com/headroomlabs-ai/headroom/issues/4470)) ([3c1fcbd](https://github.com/headroomlabs-ai/headroom/commit/3c1fcbdfde31069795b03faf9f43fdd73e6941d9))
* **core:** case-insensitive Bearer scheme, clamp SQLite CCR TTLs, redact the Redis URL in logs ([#4561](https://github.com/headroomlabs-ai/headroom/issues/4561)) ([9e8cc64](https://github.com/headroomlabs-ai/headroom/commit/9e8cc64b48ebd4e2fb31332f261464d3bd0550b7))
* **dedup:** bound line-number digit run and never fold into a longer pointer ([#4488](https://github.com/headroomlabs-ai/headroom/issues/4488)) ([21e8867](https://github.com/headroomlabs-ai/headroom/commit/21e8867504df57c8f99aa30bd889e7eed01cd49e))
* **deps:** clear the glob and minimatch npm audit findings ([#4599](https://github.com/headroomlabs-ai/headroom/issues/4599)) ([2e49e53](https://github.com/headroomlabs-ai/headroom/commit/2e49e5304b245fdaca0d2640bb1a59cb1ffa63fc))
* **diff:** keep combined-diff changes made against a later parent ([#4318](https://github.com/headroomlabs-ai/headroom/issues/4318)) ([4b788fd](https://github.com/headroomlabs-ai/headroom/commit/4b788fd04d407cea0113c74f979f7cc3072a0132))
* **docker:** install the redis extra in every image ([#4514](https://github.com/headroomlabs-ai/headroom/issues/4514)) ([8d5dde7](https://github.com/headroomlabs-ai/headroom/commit/8d5dde77656c9bb3daa354a14ffa6904cb8311aa))
* **docker:** pass RUNTIME_HOME=/root for root bake targets ([#4445](https://github.com/headroomlabs-ai/headroom/issues/4445)) ([670767e](https://github.com/headroomlabs-ai/headroom/commit/670767eeb49f224a7a0bcbcc31b3584a35110b7d))
* **doctor:** detect root openai_base_url Codex routing and agent-configured proxy ports ([#4490](https://github.com/headroomlabs-ai/headroom/issues/4490)) ([222f2d1](https://github.com/headroomlabs-ai/headroom/commit/222f2d1df3c6296462bc38c871cd29c221af55bc))
* **evals:** reject changed numeric probe values ([#4502](https://github.com/headroomlabs-ai/headroom/issues/4502)) ([1fe8549](https://github.com/headroomlabs-ai/headroom/commit/1fe8549f9ca77a2bc1280e4319980e0b9b31f5b9))
* **install:** stabilize Windows task lifecycle and eliminate console window popup ([#4627](https://github.com/headroomlabs-ai/headroom/issues/4627)) ([6b903cb](https://github.com/headroomlabs-ai/headroom/commit/6b903cbc81c13f417485f059aa6ef7aca6b0c4ec))
* **install:** tolerate absent Windows tasks in stop_supervisor ([#4465](https://github.com/headroomlabs-ai/headroom/issues/4465)) ([#4468](https://github.com/headroomlabs-ai/headroom/issues/4468)) ([50af2ff](https://github.com/headroomlabs-ai/headroom/commit/50af2ff7a81efb89d6752374a811be4fa2eec6f6))
* **kompress:** keep words past the tokenizer's truncation point ([#4328](https://github.com/headroomlabs-ai/headroom/issues/4328)) ([bb13384](https://github.com/headroomlabs-ai/headroom/commit/bb13384829069e7e0559fccf77620891e0c90be0))
* **kompress:** read the pinned snapshot from Python's one HF cache in the native proxy ([#4438](https://github.com/headroomlabs-ai/headroom/issues/4438)) ([eef44f6](https://github.com/headroomlabs-ai/headroom/commit/eef44f60cc56118a0de98455012cc18ff3eaafbd))
* **langgraph:** replace the compressed ToolMessage in graph state ([#4620](https://github.com/headroomlabs-ai/headroom/issues/4620)) ([70a8f09](https://github.com/headroomlabs-ai/headroom/commit/70a8f0979e585aa4e9b6f663fa7528340fb4efd6))
* **mcp:** confine headroom_read to the workspace (GHSA-8g49-pg6g-xgrf) ([#4525](https://github.com/headroomlabs-ai/headroom/issues/4525)) ([8ab2e91](https://github.com/headroomlabs-ai/headroom/commit/8ab2e914687266f5b602f6d3a78f13026fd5ef88))
* **memory:** bound verb-pattern word runs to stop quadratic backtracking in bridge import ([#4370](https://github.com/headroomlabs-ai/headroom/issues/4370)) ([#4376](https://github.com/headroomlabs-ai/headroom/issues/4376)) ([d232d09](https://github.com/headroomlabs-ai/headroom/commit/d232d097cf33d92f3a5112c14a306ba4a80330ee))
* **memory:** fail close unresolved project operations ([#2637](https://github.com/headroomlabs-ai/headroom/issues/2637)) ([957ab18](https://github.com/headroomlabs-ai/headroom/commit/957ab1830d73a39ba7662ee9b01dd22c7abd403e))
* **memory:** keep learned evidence until persistence succeeds ([#4229](https://github.com/headroomlabs-ai/headroom/issues/4229)) ([662a7f6](https://github.com/headroomlabs-ai/headroom/commit/662a7f6fd836ca87db5f2093c6487b500e8da2eb))
* **memory:** preserve parent scopes when clearing memories ([#4305](https://github.com/headroomlabs-ai/headroom/issues/4305)) ([a8375a1](https://github.com/headroomlabs-ai/headroom/commit/a8375a1d26c5fc6dd619bfa7a50a15bbba18acf3))
* **mixed-content:** do not carve ISO-timestamped log rows as search results ([#4463](https://github.com/headroomlabs-ai/headroom/issues/4463)) ([abbade9](https://github.com/headroomlabs-ai/headroom/commit/abbade9b4c761a82f711d0687703d0409fbe6edc))
* **offline:** guard the learn and memory-eval LLM calls under HEADROOM_OFFLINE ([#4344](https://github.com/headroomlabs-ai/headroom/issues/4344)) ([dd361bb](https://github.com/headroomlabs-ai/headroom/commit/dd361bb7a3a1d3f2e3c7572bf544ea4ea895b0a5))
* **openclaw/release:** ship responsive npm integrations ([#1458](https://github.com/headroomlabs-ai/headroom/issues/1458)) ([33f2044](https://github.com/headroomlabs-ai/headroom/commit/33f204406cc670588b9a873678b74b4af6ca3620))
* **openclaw:** record turn advancements as one marker file per key ([#4212](https://github.com/headroomlabs-ai/headroom/issues/4212)) ([24acbe8](https://github.com/headroomlabs-ai/headroom/commit/24acbe8f32b6d49e3f61097398330e7529729d3e))
* **opencode:** only route POST requests to LLM endpoint paths ([#4464](https://github.com/headroomlabs-ai/headroom/issues/4464)) ([336d462](https://github.com/headroomlabs-ai/headroom/commit/336d46225370c946ad8420ecb3f6bac81193e2f7))
* **opencode:** route Copilot Claude models through the proxy ([#4594](https://github.com/headroomlabs-ai/headroom/issues/4594)) ([3d9a6f2](https://github.com/headroomlabs-ai/headroom/commit/3d9a6f2cf7fefa2cd0d347521e0050d604a50d22))
* **output-savings:** rewrite a pre-rule ledger once instead of warning on every /stats poll ([#4196](https://github.com/headroomlabs-ai/headroom/issues/4196)) ([96e81ac](https://github.com/headroomlabs-ai/headroom/commit/96e81ac6703dcfcf4535f989319d677775e2384d))
* **packaging:** rename the sandbox extra to lean and correct SECURITY.md claims ([#3727](https://github.com/headroomlabs-ai/headroom/issues/3727)) ([09b7e8c](https://github.com/headroomlabs-ai/headroom/commit/09b7e8c1e41779b4c22f1a4ec941b59a61e621f1))
* **packaging:** use direct CLI module entry point ([#2665](https://github.com/headroomlabs-ai/headroom/issues/2665)) ([2892214](https://github.com/headroomlabs-ai/headroom/commit/28922148816b2b6ebf192abfcd6e65db8bb71511))
* **pipeline:** store the pipeline input in CCR behind offload markers ([#4576](https://github.com/headroomlabs-ai/headroom/issues/4576)) ([4d7765c](https://github.com/headroomlabs-ai/headroom/commit/4d7765c84b06d1a8630faa32a897a39a40261cd1))
* **pricing:** add Claude Haiku 5.5 rates, 1M context and its 100K long-prompt card ([#4037](https://github.com/headroomlabs-ai/headroom/issues/4037)) ([703755e](https://github.com/headroomlabs-ai/headroom/commit/703755e873d3af74b89d25792c7c9869322b0467))
* **privacy:** turn off Mem0's PostHog telemetry by default ([#4619](https://github.com/headroomlabs-ai/headroom/issues/4619)) ([fe69f38](https://github.com/headroomlabs-ai/headroom/commit/fe69f381168035ea6527bb7b908d11eeeb01838f))
* **providers:** isolate resolved Anthropic context limits ([#4593](https://github.com/headroomlabs-ai/headroom/issues/4593)) ([51258ef](https://github.com/headroomlabs-ai/headroom/commit/51258ef14a987b2c3137027e0c90f586eb290462))
* **proxy/memory:** harden _extract_tool_calls against malformed choices and blocks ([#2483](https://github.com/headroomlabs-ai/headroom/issues/2483)) ([effa5a5](https://github.com/headroomlabs-ai/headroom/commit/effa5a5886be7e3c5bc553b86da5b506046d461f))
* **proxy:** allow loopback-published container hosts to access /debug/memory ([#4259](https://github.com/headroomlabs-ai/headroom/issues/4259)) ([e546e71](https://github.com/headroomlabs-ai/headroom/commit/e546e71aeb32c355584d37abb61e8d587efce0c3))
* **proxy:** answer /api/hello probes behind the token gate, log rejection context ([#4150](https://github.com/headroomlabs-ai/headroom/issues/4150)) ([673831a](https://github.com/headroomlabs-ai/headroom/commit/673831a456ef0f551de8dc3b2cbb0deae3861c65))
* **proxy:** cap cache_control breakpoints on OpenAI chat path ([#4471](https://github.com/headroomlabs-ai/headroom/issues/4471)) ([#4491](https://github.com/headroomlabs-ai/headroom/issues/4491)) ([55602fc](https://github.com/headroomlabs-ai/headroom/commit/55602fc1e207e7101917e45bf6dba30ce544558c))
* **proxy:** do not book Gemini countTokens as a request outcome ([#4412](https://github.com/headroomlabs-ai/headroom/issues/4412)) ([4d2dd62](https://github.com/headroomlabs-ai/headroom/commit/4d2dd62b7c61724497b4bde33ef8685717f6a682))
* **proxy:** don't fail startup when libc_ver() can't read the interpreter ([#4519](https://github.com/headroomlabs-ai/headroom/issues/4519)) ([28172a9](https://github.com/headroomlabs-ai/headroom/commit/28172a921f4e3945aa43061a9e5cdd0ffd066c0e))
* **proxy:** forward Copilot accounting headers on streaming path ([#4431](https://github.com/headroomlabs-ai/headroom/issues/4431)) ([66023a0](https://github.com/headroomlabs-ai/headroom/commit/66023a0187b3260747ece4e99e6932098805442a))
* **proxy:** handle ClientDisconnect in anthropic_messages ([#3532](https://github.com/headroomlabs-ai/headroom/issues/3532)) ([251d149](https://github.com/headroomlabs-ai/headroom/commit/251d149a13ae482c1a0843d899b0321e175ac66d))
* **proxy:** honor x-headroom-base-url on provider passthrough routes ([#4596](https://github.com/headroomlabs-ai/headroom/issues/4596)) ([5c8772b](https://github.com/headroomlabs-ai/headroom/commit/5c8772b7210caeb291a202a58d4b5e88d51ff35b))
* **proxy:** install SOCKS support for websocket proxies ([#3357](https://github.com/headroomlabs-ai/headroom/issues/3357)) ([79181ca](https://github.com/headroomlabs-ai/headroom/commit/79181ca0fe35798b25104ff93b2c3a6c38baa72c))
* **proxy:** keep Gemini memory context on entries with non-text parts ([#4506](https://github.com/headroomlabs-ai/headroom/issues/4506)) ([35a2b76](https://github.com/headroomlabs-ai/headroom/commit/35a2b763f09bb147888aeeec69f72d1ed3ae872b))
* **proxy:** keep health probes and the Codex attestation out of the proxy log ([#4611](https://github.com/headroomlabs-ai/headroom/issues/4611)) ([78736a1](https://github.com/headroomlabs-ai/headroom/commit/78736a16bc46ee0bd86b7aae8ef04f7f9cfa9d6d))
* **proxy:** keep read maturation out of the provider-confirmed prefix ([#4522](https://github.com/headroomlabs-ai/headroom/issues/4522)) ([526e06b](https://github.com/headroomlabs-ai/headroom/commit/526e06b7e0120820e5b1be44b4ded70698bb86c8))
* **proxy:** keep tool deferral on Copilot Business/Enterprise/Individual hosts ([#4608](https://github.com/headroomlabs-ai/headroom/issues/4608)) ([be456d4](https://github.com/headroomlabs-ai/headroom/commit/be456d4e3f46c7f4dae725c2dd150324000c724f))
* **proxy:** log unknown model ids as one bounded token; skip unparseable PERF lines ([#4374](https://github.com/headroomlabs-ai/headroom/issues/4374)) ([c014bd6](https://github.com/headroomlabs-ai/headroom/commit/c014bd6311742e35c86ef64adfbec88ab264ef28))
* **proxy:** preserve response cache keys across in-place hooks ([#4457](https://github.com/headroomlabs-ai/headroom/issues/4457)) ([03590cd](https://github.com/headroomlabs-ai/headroom/commit/03590cd61e17ad1ef313e38a35932f729ff0c871))
* **proxy:** recognise every local spelling of the proxy in the cc-switch loop guard ([#4405](https://github.com/headroomlabs-ai/headroom/issues/4405)) ([d9958bf](https://github.com/headroomlabs-ai/headroom/commit/d9958bfdff047ff2a7ef26f9e29fc7263f790346))
* **proxy:** reconcile Chat content-block cache markers after prefix replay ([#4333](https://github.com/headroomlabs-ai/headroom/issues/4333)) ([35ca9b8](https://github.com/headroomlabs-ai/headroom/commit/35ca9b835616f7923eab23e99e9561a8da452f9f))
* **proxy:** route /v1/models to the x-headroom-base-url upstream ([#4308](https://github.com/headroomlabs-ai/headroom/issues/4308)) ([6ef52c2](https://github.com/headroomlabs-ai/headroom/commit/6ef52c2047688e41c7903a0331149a915f20d6b3))
* **proxy:** skip memory-context search in cache mode on OpenAI routes ([#4632](https://github.com/headroomlabs-ai/headroom/issues/4632)) ([365f6fe](https://github.com/headroomlabs-ai/headroom/commit/365f6fe5233c4e102584ee4c3e7a140aeccb6a75))
* **proxy:** skip memory-context search on OpenAI paths in cache mode ([#4634](https://github.com/headroomlabs-ai/headroom/issues/4634)) ([3654037](https://github.com/headroomlabs-ai/headroom/commit/36540379e0dee0c071e3a3ff00bea9b16eb3902a))
* **proxy:** skip the memory-context search in cache mode ([#4606](https://github.com/headroomlabs-ai/headroom/issues/4606)) ([053925b](https://github.com/headroomlabs-ai/headroom/commit/053925b03c6cae028731634f0ad3557518f931d5))
* **proxy:** strip only one leading space from SSE field values ([#4306](https://github.com/headroomlabs-ai/headroom/issues/4306)) ([9226eaf](https://github.com/headroomlabs-ai/headroom/commit/9226eaf3852f6d7462ebb95e6d09af3b33eb53c3))
* **proxy:** strip upstream transport framing headers from Gemini response replays ([#4605](https://github.com/headroomlabs-ai/headroom/issues/4605)) ([dfcac78](https://github.com/headroomlabs-ai/headroom/commit/dfcac78119b7038b2e20ad38cead2f4e7fe60c43))
* **read-lifecycle:** keep Reads fresh after a failed Edit or Write ([#4461](https://github.com/headroomlabs-ai/headroom/issues/4461)) ([4c3799f](https://github.com/headroomlabs-ai/headroom/commit/4c3799fd81567cd516cdc5c1463f23cea99d6594))
* **relevance:** cap embedding batch size so ORT's arena stays small ([#4507](https://github.com/headroomlabs-ai/headroom/issues/4507)) ([a2d4fe7](https://github.com/headroomlabs-ai/headroom/commit/a2d4fe72381e186651466ee94e92ce9d8d1396cc))
* **relevance:** hand the embedding arena back after each run on macOS ([#4567](https://github.com/headroomlabs-ai/headroom/issues/4567)) ([2363f83](https://github.com/headroomlabs-ai/headroom/commit/2363f833092052227a9b98a9e21a0b1a69647eab))
* **relevance:** load the Rust default embedder from Python's pinned snapshot ([#4190](https://github.com/headroomlabs-ai/headroom/issues/4190)) ([9bb4b13](https://github.com/headroomlabs-ai/headroom/commit/9bb4b130ff87a2914a8f74dbcc6b49b49c3c87a8))
* **router:** keep small shell results verbatim ([#3590](https://github.com/headroomlabs-ai/headroom/issues/3590)) ([#4426](https://github.com/headroomlabs-ai/headroom/issues/4426)) ([4ee6164](https://github.com/headroomlabs-ai/headroom/commit/4ee616453fcebed5ab7ce847e1da1016c827a4ed))
* **router:** preserve read protection for quiet sed options ([#4521](https://github.com/headroomlabs-ai/headroom/issues/4521)) ([312ffec](https://github.com/headroomlabs-ai/headroom/commit/312ffec8ead5c8c93b8f4c794ca7f588a7b84bd2))
* **router:** validate lossless provider output on the excluded-tool path ([#4486](https://github.com/headroomlabs-ai/headroom/issues/4486)) ([9f068a6](https://github.com/headroomlabs-ai/headroom/commit/9f068a6c135730c1bd4f1d800083f9318a3067a4))
* **scripts:** resolve hooks dir via git so install-git-hooks works in linked worktrees ([#4176](https://github.com/headroomlabs-ai/headroom/issues/4176)) ([0f4275f](https://github.com/headroomlabs-ai/headroom/commit/0f4275f8b331f3db14c41d958c85180a3c70a318))
* **sdk:** carry Vercel AI SDK reasoning parts and provider options through compression ([#4564](https://github.com/headroomlabs-ai/headroom/issues/4564)) ([a26faae](https://github.com/headroomlabs-ai/headroom/commit/a26faaeee34ecfde57608aea4a1ec7ea2b33272f))
* **sdk:** send Anthropic messages to /v1/compress natively so thinking blocks survive ([#4489](https://github.com/headroomlabs-ai/headroom/issues/4489)) ([cd5e2b9](https://github.com/headroomlabs-ai/headroom/commit/cd5e2b9e73eb8bd783ab872bdda71263b941e2d3))
* **security:** lstat before narrowing sqlite files ([#4527](https://github.com/headroomlabs-ai/headroom/issues/4527)) ([2cf64ef](https://github.com/headroomlabs-ai/headroom/commit/2cf64ef0cc918c7cdb3de98d56f48fdc9c4c2b4b))
* **smart-crusher:** preserve unchanged JSON bytes ([#4044](https://github.com/headroomlabs-ai/headroom/issues/4044)) ([93279f3](https://github.com/headroomlabs-ai/headroom/commit/93279f3208b1afffdbba87c2fdecbeea246d5234))
* **tabular:** keep empty records and separator-like Markdown body rows ([#4582](https://github.com/headroomlabs-ai/headroom/issues/4582)) ([5cebb90](https://github.com/headroomlabs-ai/headroom/commit/5cebb90db1f179b00eafdf79568efbc98c8ef366))
* **tabular:** keep interior blank CSV rows instead of dropping them ([#4563](https://github.com/headroomlabs-ai/headroom/issues/4563)) ([8c360ca](https://github.com/headroomlabs-ai/headroom/commit/8c360ca69fd3fc9cd6bc1e4b02109c1e5595385c))
* **thinking:** isolate compaction memo by compressor instance ([#4569](https://github.com/headroomlabs-ai/headroom/issues/4569)) ([5dcb1e4](https://github.com/headroomlabs-ai/headroom/commit/5dcb1e4adec4f6e82d943488d8aecb8967753e4e))
* **thinking:** leave a thinking block with a null or non-string value unchanged ([#4562](https://github.com/headroomlabs-ai/headroom/issues/4562)) ([cc1eb54](https://github.com/headroomlabs-ai/headroom/commit/cc1eb5402aade58204b96b6b4b4d280cdd5456d2))
* **toin:** preserve stores that exceed the byte limit ([#4589](https://github.com/headroomlabs-ai/headroom/issues/4589)) ([f9cae66](https://github.com/headroomlabs-ai/headroom/commit/f9cae66b6b19d6e6acfa4bf6da031642c256404a))
* **toin:** retain pending changes after filesystem save failures ([#4568](https://github.com/headroomlabs-ai/headroom/issues/4568)) ([8b15a15](https://github.com/headroomlabs-ai/headroom/commit/8b15a15799898d8c0a396ca0d39f951be4e0cfcf))
* **toin:** skip a malformed pattern instead of aborting the store load ([#4484](https://github.com/headroomlabs-ai/headroom/issues/4484)) ([8b628d9](https://github.com/headroomlabs-ai/headroom/commit/8b628d968574053b26849b21e5cea2e2593691c5))
* **tokenizers:** coerce structured text values in message token counters ([#4472](https://github.com/headroomlabs-ai/headroom/issues/4472)) ([6cc27a4](https://github.com/headroomlabs-ai/headroom/commit/6cc27a453d9cf69c76dc8134eb6739891471716e))
* **tokenizers:** don't cache token-count inputs larger than max_chars ([#4469](https://github.com/headroomlabs-ai/headroom/issues/4469)) ([aebb729](https://github.com/headroomlabs-ai/headroom/commit/aebb729ef3f03bee8852d067c365f075957638f9))
* **tokenizers:** price Anthropic document blocks by page count, not as ([fc1ba89](https://github.com/headroomlabs-ai/headroom/commit/fc1ba891bff2d1e0cb53c4ffd4037f5066988c8e))
* **tokenizers:** price Anthropic document blocks by page count, not as base64 text ([#4441](https://github.com/headroomlabs-ai/headroom/issues/4441)) ([fc1ba89](https://github.com/headroomlabs-ai/headroom/commit/fc1ba891bff2d1e0cb53c4ffd4037f5066988c8e))
* **tokenizers:** resolve tiktoken encoding for gateway-prefixed model ids ([#4637](https://github.com/headroomlabs-ai/headroom/issues/4637)) ([e9331b6](https://github.com/headroomlabs-ai/headroom/commit/e9331b6b963b5b6554f45943abed2366aaa25ea6))
* **transforms:** enforce role, mutable, and cache zone guards in batch compression ([#4480](https://github.com/headroomlabs-ai/headroom/issues/4480)) ([#4494](https://github.com/headroomlabs-ai/headroom/issues/4494)) ([40cd7e7](https://github.com/headroomlabs-ai/headroom/commit/40cd7e7503c66a903ac88e6a090aa0bdac7b315d))
* **transforms:** honour Subscription toin_read_only when the router calls SmartCrusher ([#4493](https://github.com/headroomlabs-ai/headroom/issues/4493)) ([7c11d46](https://github.com/headroomlabs-ai/headroom/commit/7c11d462e6d8265a2cfdb8a1cf62026fb4d1f401))
* **transforms:** preserve YAML block scalar data during comment elision ([#4498](https://github.com/headroomlabs-ai/headroom/issues/4498)) ([534cec0](https://github.com/headroomlabs-ai/headroom/commit/534cec0e14db48e787ada13535e0763fc7c52e8e))
* **transforms:** recognise code fences whose info string is not a bare word ([#4291](https://github.com/headroomlabs-ai/headroom/issues/4291)) ([a8df6f9](https://github.com/headroomlabs-ai/headroom/commit/a8df6f919f1c4730971fc2481fd18853ddcfe6b9))
* **transforms:** stop an embedded markdown table from dropping the rest of a tool result ([#4216](https://github.com/headroomlabs-ai/headroom/issues/4216)) ([b66c9c7](https://github.com/headroomlabs-ai/headroom/commit/b66c9c7db6fb7314c366fd2c28866d0ab688f211))
* **transforms:** tolerate malformed assistant tool calls in ContentRouter.apply ([#4459](https://github.com/headroomlabs-ai/headroom/issues/4459)) ([cddd2fd](https://github.com/headroomlabs-ai/headroom/commit/cddd2fd60ed711d7fc1df75b1d5e1cac947ae6c8))
* **update-check:** skip releases with no files and do not fall back to an uninstallable version ([#4560](https://github.com/headroomlabs-ai/headroom/issues/4560)) ([c1dae5a](https://github.com/headroomlabs-ai/headroom/commit/c1dae5adae2b93871314143bba4cb03b7b971e05))
* use all user text blocks for relevance scoring ([#4628](https://github.com/headroomlabs-ai/headroom/issues/4628)) ([12dca26](https://github.com/headroomlabs-ai/headroom/commit/12dca26aa11d99b3af6c6d68cdf96ff90ef415aa))
* **wrap:** overwrite drifted selfheal hook command instead of skipping it ([#2723](https://github.com/headroomlabs-ai/headroom/issues/2723)) ([2643f34](https://github.com/headroomlabs-ai/headroom/commit/2643f34a542d944ba3ad4a0a574b5e9e9d9bd474))
* **wrap:** route OMP OpenAI providers through Headroom ([#2755](https://github.com/headroomlabs-ai/headroom/issues/2755)) ([fae1e84](https://github.com/headroomlabs-ai/headroom/commit/fae1e849cb59c85cfbd46e76a05e6c299e446b02))
### Dependencies
* Bump @anthropic-ai/sdk from 0.133.0 to 1.3.0 in /sdk/typescript ([#4554](https://github.com/headroomlabs-ai/headroom/issues/4554)) ([74277d4](https://github.com/headroomlabs-ai/headroom/commit/74277d47ecfbca349ddb99f81094c4dd30539d43))
* Bump lru from 0.18.5 to 0.19.0 ([#4382](https://github.com/headroomlabs-ai/headroom/issues/4382)) ([038af59](https://github.com/headroomlabs-ai/headroom/commit/038af599e1a3c5e7e6b3047781aaf9ba2bbbf8bd))
* bump ruff from 0.17.0 to 0.17.2 in the pip-minor-patch group across 1 directory ([#4380](https://github.com/headroomlabs-ai/headroom/issues/4380)) ([64f43bd](https://github.com/headroomlabs-ai/headroom/commit/64f43bdf8f2080d5d7c1874fe1572acbb05872b6))
* bump ruff from 0.17.2 to 0.17.3 in the pip-minor-patch group ([#4652](https://github.com/headroomlabs-ai/headroom/issues/4652)) ([cb9602a](https://github.com/headroomlabs-ai/headroom/commit/cb9602aef0e4914f723a33ef6bad3a7c06eb485a))
* Bump the cargo-minor-patch group across 1 directory with 12 updates ([#4553](https://github.com/headroomlabs-ai/headroom/issues/4553)) ([b9049d7](https://github.com/headroomlabs-ai/headroom/commit/b9049d703af340ff90ed867f86e5fafa10c155c9))
* Bump the npm-minor-patch group across 1 directory with 6 updates ([#4621](https://github.com/headroomlabs-ai/headroom/issues/4621)) ([5e4827d](https://github.com/headroomlabs-ai/headroom/commit/5e4827de12c9fdf33d7d36b1939eee73a18fe6c5))
* Bump the npm-minor-patch group across 2 directories with 14 updates ([#4455](https://github.com/headroomlabs-ai/headroom/issues/4455)) ([f10725e](https://github.com/headroomlabs-ai/headroom/commit/f10725e6b9940d8bc2fcde950c86f8ac97543cb6))
* Bump the npm-minor-patch group across 3 directories with 9 updates ([#4495](https://github.com/headroomlabs-ai/headroom/issues/4495)) ([f367728](https://github.com/headroomlabs-ai/headroom/commit/f36772805178e3fed1a95313e8211c57a291b953))
* Bump tsup from 8.5.1 to 9.0.0 in /plugins/openclaw ([#4384](https://github.com/headroomlabs-ai/headroom/issues/4384)) ([9d87151](https://github.com/headroomlabs-ai/headroom/commit/9d871516101ff5428b592acb213aeacd30afc328))
* Bump tsup from 8.5.1 to 9.0.0 in /plugins/opencode ([#4385](https://github.com/headroomlabs-ai/headroom/issues/4385)) ([99e223c](https://github.com/headroomlabs-ai/headroom/commit/99e223c0e2c2ea6eb88ce28b160ae179897a9c67))
* Bump tsup from 8.5.1 to 9.0.0 in /sdk/typescript ([#4386](https://github.com/headroomlabs-ai/headroom/issues/4386)) ([e666fd8](https://github.com/headroomlabs-ai/headroom/commit/e666fd8e35dbe7c0433739297873b6a0a51c26cf))
* qualify latest Anthropic SDK 1.4.0 in docs ([#4556](https://github.com/headroomlabs-ai/headroom/issues/4556)) ([65bcc4c](https://github.com/headroomlabs-ai/headroom/commit/65bcc4c313aadfb609973563573b8bb3f308d81f))
* qualify latest compatible docs and E2E tools ([#4580](https://github.com/headroomlabs-ai/headroom/issues/4580)) ([e42f74e](https://github.com/headroomlabs-ai/headroom/commit/e42f74ebc9a784014ad9799b75f862efe4bf69e3))
* require Python 3.11; clear Dependabot alerts in the 3.10 lock fork ([#4517](https://github.com/headroomlabs-ai/headroom/issues/4517)) ([3c6f82b](https://github.com/headroomlabs-ai/headroom/commit/3c6f82b06091206379106f8fe1a54f2400ed7a93))
* update tomlkit requirement from <1.0,>=0.15.0 to >=0.15.2,<1.0 ([#4653](https://github.com/headroomlabs-ai/headroom/issues/4653)) ([00d5a5c](https://github.com/headroomlabs-ai/headroom/commit/00d5a5ca619f6e23da54d8b7e3fa4cc7af444035))
## [0.42.0](https://github.com/headroomlabs-ai/headroom/compare/v0.41.0...v0.42.0) (2026-10-26)
### Features
* **pipeline:** put per-request saved tokens on OutcomeSnapshot ([#4231](https://github.com/headroomlabs-ai/headroom/issues/4231)) ([8cedf7b](https://github.com/headroomlabs-ai/headroom/commit/8cedf7be4decfb3a0da42e4e955b6a3301a66dc9))
* **proxy:** let turn hooks rewrite OpenAI Responses requests on HTTP and WebSocket ([#4232](https://github.com/headroomlabs-ai/headroom/issues/4232)) ([fbf7bc3](https://github.com/headroomlabs-ai/headroom/commit/fbf7bc3278c11975299b9bd0a2ecf200dfd25a05))
* **proxy:** report the same tool savings on gateway /v1/compress as the proxy path ([#4467](https://github.com/headroomlabs-ai/headroom/issues/4467)) ([a904210](https://github.com/headroomlabs-ai/headroom/commit/a90421083a781990b877d34fdaba0bc1b6cf6c4d))
* **savings:** add the per-request counterfactual savings record ([#4236](https://github.com/headroomlabs-ai/headroom/issues/4236)) ([2912b7b](https://github.com/headroomlabs-ai/headroom/commit/2912b7b620d7abd39828db73e4f326b9a041d309))
### Bug Fixes
* **batch:** preserve live contexts during capacity cleanup ([#4210](https://github.com/headroomlabs-ai/headroom/issues/4210)) ([2cbdd22](https://github.com/headroomlabs-ai/headroom/commit/2cbdd22a65789676d9ebbd9e2b6a908e7f8fad95))
* **batch:** preserve native Gemini continuation tools ([#4211](https://github.com/headroomlabs-ai/headroom/issues/4211)) ([8757458](https://github.com/headroomlabs-ai/headroom/commit/875745889ff065208d3a32aa583881468ae7c41d))
* **cache:** bound the router's compression cache, keep the rest in SQLite ([#4357](https://github.com/headroomlabs-ai/headroom/issues/4357)) ([b196424](https://github.com/headroomlabs-ai/headroom/commit/b196424e35df0afc0c8576aea1950ed16b00e027))
* **cache:** keep indented lines intact in OpenAI whitespace normalization ([#4343](https://github.com/headroomlabs-ai/headroom/issues/4343)) ([2480100](https://github.com/headroomlabs-ai/headroom/commit/248010091578e1f05ebcf65c8146bb57f9fb4e00))
* **cache:** keep prefix-tracker state across a graceful proxy restart ([#4299](https://github.com/headroomlabs-ai/headroom/issues/4299)) ([62b3bed](https://github.com/headroomlabs-ai/headroom/commit/62b3bedaba988de87e38b1a58c11d28baaba7dbf))
* **ccr:** recognize client-owned MCP retrieval aliases ([#4165](https://github.com/headroomlabs-ai/headroom/issues/4165)) ([89545fb](https://github.com/headroomlabs-ai/headroom/commit/89545fbdf3873f75461f71a03c89b1f9c64d650d))
* **ccr:** stream the buffered CCR upstream request so idle-killing networks cannot cut it ([#4206](https://github.com/headroomlabs-ai/headroom/issues/4206)) ([ca6ba34](https://github.com/headroomlabs-ai/headroom/commit/ca6ba3486c09badecb1bfe99ddabf562c9f01c77))
* **ci:** pin checkout in release notification smoke workflow ([#4399](https://github.com/headroomlabs-ai/headroom/issues/4399)) ([70273db](https://github.com/headroomlabs-ai/headroom/commit/70273db0af392e8f971d42e21484656676255d0b))
* **copilot:** detect COPILOT_API_URL in cli-main.js for Copilot CLI >= 1.0.93 ([#4450](https://github.com/headroomlabs-ai/headroom/issues/4450)) ([043fe09](https://github.com/headroomlabs-ai/headroom/commit/043fe09d8c620201045619bcbcd88e26e2c6e71f))
* **copilot:** preserve native inline OAuth identity ([#4144](https://github.com/headroomlabs-ai/headroom/issues/4144)) ([ad62166](https://github.com/headroomlabs-ai/headroom/commit/ad62166ba3056e5b98fc5bfee19f0c9b6c316e8d))
* **deps:** bump rustls to 0.23.46 for RUSTSEC-2026-0346..0349 ([#4222](https://github.com/headroomlabs-ai/headroom/issues/4222)) ([132dbc7](https://github.com/headroomlabs-ai/headroom/commit/132dbc76995cdbecc25b4f647dbf919351cd5f7f))
* **deps:** patch OpenClaw Undici and narrow E2E audit exceptions ([#4453](https://github.com/headroomlabs-ai/headroom/issues/4453)) ([1be699f](https://github.com/headroomlabs-ai/headroom/commit/1be699f68ee884c5c319cee9841ca304e448873c))
* **deps:** require hf-xet>=1.6.0 so a Hub download can't crash Python at exit ([#4192](https://github.com/headroomlabs-ai/headroom/issues/4192)) ([9e5dac7](https://github.com/headroomlabs-ai/headroom/commit/9e5dac7c74979abd8d1b9ad9615443b76e42b530))
* **deps:** require mcp>=1.30.0 for CVE-2026-59951 ([#4239](https://github.com/headroomlabs-ai/headroom/issues/4239)) ([2f7a83a](https://github.com/headroomlabs-ai/headroom/commit/2f7a83a91d3ca33a79b5c41b8095f6454b5bfb43))
* **gateway:** keep input_includes_cache when re-drive usage is merged ([#4423](https://github.com/headroomlabs-ai/headroom/issues/4423)) ([3f94144](https://github.com/headroomlabs-ai/headroom/commit/3f941446bfbeb0b66cf6eb4a1ddf254e17d0c2a4))
* **gemini:** keep snake_case inline_data and function parts when compressing ([#4290](https://github.com/headroomlabs-ai/headroom/issues/4290)) ([4bf1bf5](https://github.com/headroomlabs-ai/headroom/commit/4bf1bf55d175ad047c32cc3049aeff51126424c8))
* **image:** clear last_result before each compress() call ([#4341](https://github.com/headroomlabs-ai/headroom/issues/4341)) ([19c91a8](https://github.com/headroomlabs-ai/headroom/commit/19c91a870fac09f824001197e72c8929698ea0b8))
* **image:** flatten transparent images onto white before re-encoding as JPEG ([#4296](https://github.com/headroomlabs-ai/headroom/issues/4296)) ([9f5cfcf](https://github.com/headroomlabs-ai/headroom/commit/9f5cfcfd2bb90097f79144ff3821fc7db9fe36d5))
* **install:** keep the HuggingFace cache on a writable mount in Docker presets ([#4207](https://github.com/headroomlabs-ai/headroom/issues/4207)) ([#4209](https://github.com/headroomlabs-ai/headroom/issues/4209)) ([7b6cb77](https://github.com/headroomlabs-ai/headroom/commit/7b6cb7790552ac10f0135013337ea4a09a9e951e))
* **kompress:** skip the local model download when a remote endpoint is set ([#4234](https://github.com/headroomlabs-ai/headroom/issues/4234)) ([ff36931](https://github.com/headroomlabs-ai/headroom/commit/ff3693165344410eaf2882209648e504f9d3eaf0))
* **kompress:** time each model-load stage and stop false not-ready warnings during warm-up ([#4195](https://github.com/headroomlabs-ai/headroom/issues/4195)) ([89b229c](https://github.com/headroomlabs-ai/headroom/commit/89b229ce5feaeb8710f4e226a47697426231ca55))
* **learn:** anchor the managed block on its last start marker, append when no end marker ([#4342](https://github.com/headroomlabs-ai/headroom/issues/4342)) ([45dacc1](https://github.com/headroomlabs-ai/headroom/commit/45dacc1f94a4343c76a6e257143d22d67dc713f0))
* **learn:** keep the digest's loop section inside its budget ([#4269](https://github.com/headroomlabs-ai/headroom/issues/4269)) ([506ba16](https://github.com/headroomlabs-ai/headroom/commit/506ba16c4a7f231b177d28066bcda389133a5e91))
* **logs:** count omitted levels from dropped lines ([#4141](https://github.com/headroomlabs-ai/headroom/issues/4141)) ([023dd1b](https://github.com/headroomlabs-ai/headroom/commit/023dd1bc5402dcebf52a5ed3cf6a2a2878a524d9))
* **mcp:** accept the JSONC opencode config that wrap and install already accept ([#4297](https://github.com/headroomlabs-ai/headroom/issues/4297)) ([9202948](https://github.com/headroomlabs-ai/headroom/commit/9202948c1e57a4ab8daa7c00c400605844c19f4f))
* **memory:** bound retrieval queries before embedding ([#4244](https://github.com/headroomlabs-ai/headroom/issues/4244)) ([8c07cf4](https://github.com/headroomlabs-ai/headroom/commit/8c07cf4a0fff1b67da1b542dc746b0b4a0e952e6))
* **memory:** ignore incidental cwd prose ([#4166](https://github.com/headroomlabs-ai/headroom/issues/4166)) ([3765439](https://github.com/headroomlabs-ai/headroom/commit/37654390b60ccb7658bb96a2f177b8666c7b7273))
* **memory:** log storage and SQLite failures that currently make retrieval miss silently ([#4111](https://github.com/headroomlabs-ai/headroom/issues/4111)) ([4e6e955](https://github.com/headroomlabs-ai/headroom/commit/4e6e955cad0bff318e30bd4f24e934a23f57e9c6))
* **memory:** resolve partial IDs beyond the first 1000 records ([#4389](https://github.com/headroomlabs-ai/headroom/issues/4389)) ([c4ea31b](https://github.com/headroomlabs-ai/headroom/commit/c4ea31b156478adde015833074ad7278230b4512))
* **memory:** treat a cwd with no UTF-8 form as unresolved instead of raising ([#4167](https://github.com/headroomlabs-ai/headroom/issues/4167)) ([760c05e](https://github.com/headroomlabs-ai/headroom/commit/760c05e1b0ff8c34443f5d6eba0c4ff36f171eb2))
* **openai:** read Responses cache_write_tokens instead of inferring writes ([#4237](https://github.com/headroomlabs-ai/headroom/issues/4237)) ([4630602](https://github.com/headroomlabs-ai/headroom/commit/46306024e74b3a44aca17fb70c1416f96b2a0b53))
* **openai:** recompress cached Responses units whose CCR entries expired ([#4146](https://github.com/headroomlabs-ai/headroom/issues/4146)) ([8f7b419](https://github.com/headroomlabs-ai/headroom/commit/8f7b41998076727d08e5db4ee57c8bd579988c30))
* **opencode:** do not rewrite an OpenCode config that fails to parse ([#4424](https://github.com/headroomlabs-ai/headroom/issues/4424)) ([0fe0a59](https://github.com/headroomlabs-ai/headroom/commit/0fe0a597c1929bcb4a7372e6689fd62410bad9d2))
* **opencode:** restore process env keys on transport dispose ([#4430](https://github.com/headroomlabs-ai/headroom/issues/4430)) ([d17bac8](https://github.com/headroomlabs-ai/headroom/commit/d17bac8d64dd74ade81638ac7170715851c9704b))
* **pricing:** suppress litellm's Provider List banner that corrupts perf JSON ([#4197](https://github.com/headroomlabs-ai/headroom/issues/4197)) ([e01ad35](https://github.com/headroomlabs-ai/headroom/commit/e01ad350dc71d44f1a4e07df5ea4e45fa39a4773))
* **proxy:** accept HEADROOM_MEMORY_INJECTION_MODE=tool ([#4395](https://github.com/headroomlabs-ai/headroom/issues/4395)) ([f89c928](https://github.com/headroomlabs-ai/headroom/commit/f89c9282a8216b8e168c29d85c6f13c5ce7d6301))
* **proxy:** bound per-model state keyed by the client model string ([#4407](https://github.com/headroomlabs-ai/headroom/issues/4407)) ([33e5f67](https://github.com/headroomlabs-ai/headroom/commit/33e5f67464286961f37d09298d31c5022d275a32))
* **proxy:** copy cached tool compaction results (hardening) ([#4410](https://github.com/headroomlabs-ai/headroom/issues/4410)) ([a256231](https://github.com/headroomlabs-ai/headroom/commit/a25623109d5075276af057e79c3ed3e309906563))
* **proxy:** count output tokens from CRLF-framed SSE streams too ([#4298](https://github.com/headroomlabs-ai/headroom/issues/4298)) ([755293d](https://github.com/headroomlabs-ai/headroom/commit/755293dd68d495b6fcec15fd47d324c3ce5eeefa))
* **proxy:** do not rebuild a failed turn-hook re-drive as HTTP 200 ([#4398](https://github.com/headroomlabs-ai/headroom/issues/4398)) ([f59c8ff](https://github.com/headroomlabs-ai/headroom/commit/f59c8ffcd80f19564cf041d1fa4eb6247f2e1d01))
* **proxy:** drop web_search_call history from a Responses request with no web_search tool ([#4202](https://github.com/headroomlabs-ai/headroom/issues/4202)) ([2a70d12](https://github.com/headroomlabs-ai/headroom/commit/2a70d128195575cbc52129a5287a9a3ccc097744))
* **proxy:** honor bypass header and license gate in Anthropic batch create ([#4411](https://github.com/headroomlabs-ai/headroom/issues/4411)) ([4fd9cdd](https://github.com/headroomlabs-ai/headroom/commit/4fd9cddfd2e9cbbe38ab0b9d3acc6bc6f934a6e2))
* **proxy:** import Response at runtime in the Bedrock handler ([#4397](https://github.com/headroomlabs-ai/headroom/issues/4397)) ([51e4ae3](https://github.com/headroomlabs-ai/headroom/commit/51e4ae36a5751fc494c0b583d37e62213e5a08a9))
* **proxy:** judge NAT64 upstream addresses by their embedded IPv4 ([#4179](https://github.com/headroomlabs-ai/headroom/issues/4179)) ([486afaa](https://github.com/headroomlabs-ai/headroom/commit/486afaac7426fa1d6735fe2ce6ae37630d9d11ae))
* **proxy:** keep in-period costs in the budget ledger when the entry cap is reached ([#4448](https://github.com/headroomlabs-ai/headroom/issues/4448)) ([41c15b3](https://github.com/headroomlabs-ai/headroom/commit/41c15b311cd5ab34d5108569eef4249a60973f96))
* **proxy:** keep negative compression savings across restart ([#4406](https://github.com/headroomlabs-ai/headroom/issues/4406)) ([bebe24c](https://github.com/headroomlabs-ai/headroom/commit/bebe24c5ff0e815ac87937d9ecb1633a5091ab64))
* **proxy:** keep tool deferral for GitHub Copilot upstream ([#4356](https://github.com/headroomlabs-ai/headroom/issues/4356)) ([217b658](https://github.com/headroomlabs-ai/headroom/commit/217b658845389e32a02760d75886de20d60e2ba3))
* **proxy:** let HEADROOM_LOG_LEVEL=debug turn on Headroom's own debug logs ([#4137](https://github.com/headroomlabs-ai/headroom/issues/4137)) ([00093ce](https://github.com/headroomlabs-ai/headroom/commit/00093ceddcf42c3936a96ea5f280af2d0e1b2e47))
* **proxy:** make handler failures debuggable from the logs ([#4127](https://github.com/headroomlabs-ai/headroom/issues/4127)) ([7dc20b6](https://github.com/headroomlabs-ai/headroom/commit/7dc20b6fe027cf262c5e2d0415f0dbb2032ac73b))
* **proxy:** net tools a turn hook adds against the saving it books ([#4057](https://github.com/headroomlabs-ai/headroom/issues/4057)) ([85520c2](https://github.com/headroomlabs-ai/headroom/commit/85520c2941ed6b2c4cd4bfd9f747b24227a256aa))
* **proxy:** record a stream the client closes after its terminal event as completed ([#4286](https://github.com/headroomlabs-ai/headroom/issues/4286)) ([762a337](https://github.com/headroomlabs-ai/headroom/commit/762a337bbeba268ae1e172c7a7de1e374231e32c))
* **proxy:** record outcome when a passthrough stream ends mid-character ([#4429](https://github.com/headroomlabs-ai/headroom/issues/4429)) ([75cfbba](https://github.com/headroomlabs-ai/headroom/commit/75cfbba91d9bb2ff55df3949eddd4452dd9fb661))
* **proxy:** report disabled Kompress at startup ([#4217](https://github.com/headroomlabs-ai/headroom/issues/4217)) ([430ea4f](https://github.com/headroomlabs-ai/headroom/commit/430ea4f4ebaeb0b217e237084963b64775bef24a))
* **proxy:** report read maturation as inert in cache mode ([#4198](https://github.com/headroomlabs-ai/headroom/issues/4198)) ([ba82453](https://github.com/headroomlabs-ai/headroom/commit/ba824539d6f80c3e056f299789c1cf079a4693fe))
* **proxy:** show turn-hook savings in /stats extension_savings, incl. Codex WS ([#4233](https://github.com/headroomlabs-ai/headroom/issues/4233)) ([1d112cd](https://github.com/headroomlabs-ai/headroom/commit/1d112cd36c9aee765ec3b550773de0c93c6d79be))
* **proxy:** snapshot the original messages when a turn hook can edit them ([#4241](https://github.com/headroomlabs-ai/headroom/issues/4241)) ([df11f27](https://github.com/headroomlabs-ai/headroom/commit/df11f2749862a0090db11f7fca3e7dc42a75b612))
* **relevance:** load the default embedder from one pinned snapshot ([#4152](https://github.com/headroomlabs-ai/headroom/issues/4152)) ([f380692](https://github.com/headroomlabs-ai/headroom/commit/f380692b463637e90de84f1b5cc29c7ae9f7b969))
* **savings:** key a Responses conversation on its thread, not the shared session ([#4440](https://github.com/headroomlabs-ai/headroom/issues/4440)) ([11f743d](https://github.com/headroomlabs-ai/headroom/commit/11f743dd90e9f60cf01805a23514bd06440dd2d2))
* **sdk:** preserve Vercel AI SDK file and image parts through compression ([#4048](https://github.com/headroomlabs-ai/headroom/issues/4048)) ([1668a6c](https://github.com/headroomlabs-ai/headroom/commit/1668a6c0dd73cd8a1b9d7fc5eae297149e8f7d93))
* **security:** restrict the Windows runtime log via NTFS ACL, not just warn ([#4135](https://github.com/headroomlabs-ai/headroom/issues/4135)) ([125a703](https://github.com/headroomlabs-ai/headroom/commit/125a703a65c574e9db809f95eefdc70407e0250e))
* **smart-crusher:** match audit-safe protected_patterns against unescaped text ([#4294](https://github.com/headroomlabs-ai/headroom/issues/4294)) ([e11afdb](https://github.com/headroomlabs-ai/headroom/commit/e11afdbdf8a729e50553681143d0f925b71fcd83))
* **storage:** normalize timezone-aware JSONL time filters ([#4063](https://github.com/headroomlabs-ai/headroom/issues/4063)) ([bf34ccf](https://github.com/headroomlabs-ai/headroom/commit/bf34ccf58861a687e814abf1a158885987add9ae))
* **tabular:** pass tables with repeated header names through verbatim ([#4278](https://github.com/headroomlabs-ai/headroom/issues/4278)) ([ed3195b](https://github.com/headroomlabs-ai/headroom/commit/ed3195beef1dcfbb0219c2da9b59984167c81c01))
* **telemetry:** give empty-item compressions a stable tool signature ([#4396](https://github.com/headroomlabs-ai/headroom/issues/4396)) ([a79def4](https://github.com/headroomlabs-ai/headroom/commit/a79def4dd1b7217a75ce6c4eebd0b06ea3a70c1d))
* **telemetry:** let HEADROOM_TELEMETRY=off stop the anonymous beacon ([#4235](https://github.com/headroomlabs-ai/headroom/issues/4235)) ([1a40b3c](https://github.com/headroomlabs-ai/headroom/commit/1a40b3ce67ad9e155ba768e8d05cec4c872c7f99))
* **transforms:** keep the fences of a code block passed through for a protected tag ([#4292](https://github.com/headroomlabs-ai/headroom/issues/4292)) ([02958c6](https://github.com/headroomlabs-ai/headroom/commit/02958c6ffe41a1d3466c21558670875df87384ae))
* **transforms:** log the compression failures that silently become "no savings" ([#4092](https://github.com/headroomlabs-ai/headroom/issues/4092)) ([580cc83](https://github.com/headroomlabs-ai/headroom/commit/580cc83a9a412123040978447a2c9b77c08670b0))
* **zcode:** skip providers that point at the Headroom proxy itself ([#4413](https://github.com/headroomlabs-ai/headroom/issues/4413)) ([9ac1b52](https://github.com/headroomlabs-ai/headroom/commit/9ac1b52c2762bbc40d3e459e5f87cd4bbfbde8aa))
### Dependencies
* Bump base64 from 0.22.1 to 0.23.1 ([#4029](https://github.com/headroomlabs-ai/headroom/issues/4029)) ([8d468d4](https://github.com/headroomlabs-ai/headroom/commit/8d468d455c2e3c195cc2975bbc13e63d6b85ef59))
* Bump ruff from 0.16.8 to 0.17.0 in the pip-minor-patch group across 1 directory ([#4026](https://github.com/headroomlabs-ai/headroom/issues/4026)) ([de3f639](https://github.com/headroomlabs-ai/headroom/commit/de3f639803f1f172f65c05c165bfab92c0bec9e8))
* Bump the cargo-minor-patch group across 1 directory with 12 updates ([#4186](https://github.com/headroomlabs-ai/headroom/issues/4186)) ([683c9a6](https://github.com/headroomlabs-ai/headroom/commit/683c9a6120c309e84e4848378dbe3891d064f82e))
* Bump the npm-minor-patch group across 2 directories with 16 updates ([#4218](https://github.com/headroomlabs-ai/headroom/issues/4218)) ([07c8bbf](https://github.com/headroomlabs-ai/headroom/commit/07c8bbf1edcc143a7fe97b9e29214355cc371a19))
* Bump the npm-minor-patch group across 3 directories with 12 updates ([#4219](https://github.com/headroomlabs-ai/headroom/issues/4219)) ([1f71cb3](https://github.com/headroomlabs-ai/headroom/commit/1f71cb3d64e1586c97331a3482aae84558741102))
* Update huggingface-hub requirement from <2.0,>=1.5.0 to >=1.5.0,<3.0 ([#4027](https://github.com/headroomlabs-ai/headroom/issues/4027)) ([fcf3db8](https://github.com/headroomlabs-ai/headroom/commit/fcf3db8e70d15aef0d80a561cf5d0e45e918a338))
### Code Refactoring
* **integrations:** share the local/cloud compress backend of asgi and litellm_callback ([#4124](https://github.com/headroomlabs-ai/headroom/issues/4124)) ([58caafb](https://github.com/headroomlabs-ai/headroom/commit/58caafb59b40c00b35ceee6237ef2289df71f25d))
* **transforms:** share one CCR persist helper for the Rust-backed compressors ([#4094](https://github.com/headroomlabs-ai/headroom/issues/4094)) ([ea947ca](https://github.com/headroomlabs-ai/headroom/commit/ea947ca421ee6d6b8f15a9ed522c3a3bea5a3225))
## [0.41.0](https://github.com/headroomlabs-ai/headroom/compare/v0.40.0...v0.41.0) (2026-10-13)
### Features
* **antigravity:** add native Google Antigravity IDE integration ([#3817](https://github.com/headroomlabs-ai/headroom/issues/3817)) ([cd4367b](https://github.com/headroomlabs-ai/headroom/commit/cd4367b040bf80b7358f100da54994f6d5fbfcfe))
* **opencode:** support the OpenCode 2.x plugin API ([#3999](https://github.com/headroomlabs-ai/headroom/issues/3999)) ([1d4b357](https://github.com/headroomlabs-ai/headroom/commit/1d4b357ca745549382e1ed9a3a6d39b5df52d3d5))
* **plugins:** add headroom-snip Claude Code mod that animates compression ([#3980](https://github.com/headroomlabs-ai/headroom/issues/3980)) ([17abee2](https://github.com/headroomlabs-ai/headroom/commit/17abee2721c1946bc8903d623bec91ff6e531c17))
* **proxy:** native spend/savings stats + dashboard for the Rust proxy ([#2321](https://github.com/headroomlabs-ai/headroom/issues/2321)) ([70b21c1](https://github.com/headroomlabs-ai/headroom/commit/70b21c12c41cd128c7b8700c33b29b687de567a4))
* **router:** add max_output_tokens condition to ModelRoute ([#3898](https://github.com/headroomlabs-ai/headroom/issues/3898)) ([01185e3](https://github.com/headroomlabs-ai/headroom/commit/01185e32d393c02ae63b104429f6dbfc6cdd1da0))
* **savings:** per-agent attribution in history checkpoints and rollups ([#2627](https://github.com/headroomlabs-ai/headroom/issues/2627)) ([489de46](https://github.com/headroomlabs-ai/headroom/commit/489de468258584c69c90c798397d81e0b35ace67))
* show the Headroom for Teams offer in the dashboard, docs, llms.txt and release notes ([#3991](https://github.com/headroomlabs-ai/headroom/issues/3991)) ([1ad92f0](https://github.com/headroomlabs-ai/headroom/commit/1ad92f0cbc3dea27676e253588100f64a2af6994))
### Bug Fixes
* **anthropic:** route /api/hello connectivity probes to Anthropic ([#3336](https://github.com/headroomlabs-ai/headroom/issues/3336)) ([#4059](https://github.com/headroomlabs-ai/headroom/issues/4059)) ([931e5b9](https://github.com/headroomlabs-ai/headroom/commit/931e5b9666f4022feb38abadfbdb77c96c69e95a))
* **beacon:** stop Cloudflare logging senders' IP addresses ([#4018](https://github.com/headroomlabs-ai/headroom/issues/4018)) ([db983ba](https://github.com/headroomlabs-ai/headroom/commit/db983bacc616fec3d622e8a039b47135b1ad4166))
* **cache:** keep cache mode when Claude Code re-serializes its last reply ([#4003](https://github.com/headroomlabs-ai/headroom/issues/4003)) ([aeb09f8](https://github.com/headroomlabs-ai/headroom/commit/aeb09f8d1884318d27b05b440b44c603e1c0d727))
* **cache:** retain prefix trackers for the provider cache lifetime ([#4023](https://github.com/headroomlabs-ai/headroom/issues/4023)) ([9553d42](https://github.com/headroomlabs-ai/headroom/commit/9553d4292f949224105bfee8c29f4979a2c3092a))
* **cache:** stop Claude Code forks from cold-starting the conversation's lineage ([#4043](https://github.com/headroomlabs-ai/headroom/issues/4043)) ([1cf4d05](https://github.com/headroomlabs-ai/headroom/commit/1cf4d053d2bae276280dd3b71ebcf00cfd4d9cfc))
* **ccr:** serve headroom_retrieve when the model calls it alongside client tools ([#4034](https://github.com/headroomlabs-ai/headroom/issues/4034)) ([01d9194](https://github.com/headroomlabs-ai/headroom/commit/01d9194854233ef6ed04005cf0a5b8c32bf65d6d))
* **cli:** name the broken Codex config, write init configs atomically, keep the identity check ([#4129](https://github.com/headroomlabs-ai/headroom/issues/4129)) ([976aa71](https://github.com/headroomlabs-ai/headroom/commit/976aa714ef3e19174dc0cb586cee7b20d064e4ef))
* **cli:** pass configured SSL context to stdlib urlopen calls ([#4011](https://github.com/headroomlabs-ai/headroom/issues/4011)) ([22d0905](https://github.com/headroomlabs-ai/headroom/commit/22d0905a73d1498e1a3658427687416373c1d4a1))
* **cli:** say why the proxy failed to start ([#4120](https://github.com/headroomlabs-ai/headroom/issues/4120)) ([f3d240b](https://github.com/headroomlabs-ai/headroom/commit/f3d240bcae5f12d87925b5fa46d36eecff19ba2d))
* **codex:** make unwrap codex remove headroom init routing ([#3920](https://github.com/headroomlabs-ai/headroom/issues/3920)) ([3260795](https://github.com/headroomlabs-ai/headroom/commit/326079517b40d2bbec6d2c7a453b22be9b8b6755))
* **codex:** preserve auth.json API keys through Headroom ([#3355](https://github.com/headroomlabs-ai/headroom/issues/3355)) ([a6523b1](https://github.com/headroomlabs-ai/headroom/commit/a6523b19678af49ed1039fe946ae0cfee2181509))
* **copilot:** honour GitHub's advertised Business/Enterprise host by default ([#4155](https://github.com/headroomlabs-ai/headroom/issues/4155)) ([1dc7a18](https://github.com/headroomlabs-ai/headroom/commit/1dc7a183f55db35188aefa95f9cd4aed18377862))
* **copilot:** send VS Code next-edit requests to the completions host ([#4188](https://github.com/headroomlabs-ai/headroom/issues/4188)) ([22a1296](https://github.com/headroomlabs-ai/headroom/commit/22a1296cfabc855f9bc6e36a1bcb0f9e788f75a5))
* **dashboard:** keep savings profile visible in light mode ([#2544](https://github.com/headroomlabs-ai/headroom/issues/2544)) ([4e4f49d](https://github.com/headroomlabs-ai/headroom/commit/4e4f49d058846c44ae6061edd5a53776c03a0507))
* **dashboard:** show the effective value in settings enum selects ([#4032](https://github.com/headroomlabs-ai/headroom/issues/4032)) ([20ce054](https://github.com/headroomlabs-ai/headroom/commit/20ce054f8d34af50106daa0c8aa518231e17004b))
* **deps:** bump quinn-proto to 0.11.19 for RUSTSEC-2026-0338..0342 ([#4178](https://github.com/headroomlabs-ai/headroom/issues/4178)) ([49751ec](https://github.com/headroomlabs-ai/headroom/commit/49751ec4c797c9ff8ae7e3cdfed6c8372c7fbfcd))
* **deps:** clear the two high npm advisories failing the Security workflow ([#4004](https://github.com/headroomlabs-ai/headroom/issues/4004)) ([5a516b5](https://github.com/headroomlabs-ai/headroom/commit/5a516b54afd50156521638645a9063992e395a7b))
* **deps:** recommend headroom-ai for optional extras ([#4046](https://github.com/headroomlabs-ai/headroom/issues/4046)) ([f1bc260](https://github.com/headroomlabs-ai/headroom/commit/f1bc260948c159549d6937e9c4d2cf969256f2bb))
* **deps:** support Intel macOS ONNX Runtime resolution ([#3823](https://github.com/headroomlabs-ai/headroom/issues/3823)) ([51ec6e8](https://github.com/headroomlabs-ai/headroom/commit/51ec6e8ffef8d3c76b0dc7b283c8c5eabcd6acc2))
* **docker:** adds mount for the litellm config dir ([#2454](https://github.com/headroomlabs-ai/headroom/issues/2454)) ([64a661d](https://github.com/headroomlabs-ai/headroom/commit/64a661d5b4898d97061bfcaa10caad477b319b37))
* **gateway:** report why /v1/compress/response rejected a body ([#4081](https://github.com/headroomlabs-ai/headroom/issues/4081)) ([5cac7ab](https://github.com/headroomlabs-ai/headroom/commit/5cac7ab693c2f1e3d8dbbe4756f0e7f6fa0687d6))
* **grok:** attribute api.x.ai chat outcomes as provider xai, recognize grok-shell UA ([#2626](https://github.com/headroomlabs-ai/headroom/issues/2626)) ([b1fb162](https://github.com/headroomlabs-ai/headroom/commit/b1fb162b622327102832f15b2ca14a4613da9fcd))
* **install/windows:** back persistent-service with an always-on task ([#1866](https://github.com/headroomlabs-ai/headroom/issues/1866)) ([#2460](https://github.com/headroomlabs-ai/headroom/issues/2460)) ([5682883](https://github.com/headroomlabs-ai/headroom/commit/5682883bb03472caeb510d6ff84070d5558d0f62))
* **install:** distinguish protocol targets in status ([#4040](https://github.com/headroomlabs-ai/headroom/issues/4040)) ([79f2c27](https://github.com/headroomlabs-ai/headroom/commit/79f2c2781a1e6d5a13c75ae233e01c6d8d910ef1))
* **install:** keep an explicitly empty dashboard allowlist on Windows PowerShell 5.1 ([#4012](https://github.com/headroomlabs-ai/headroom/issues/4012)) ([c195a12](https://github.com/headroomlabs-ai/headroom/commit/c195a1220f8d3525879c87486bd63d96e870e648))
* **install:** preserve OpenCode edits during reactivation ([#4022](https://github.com/headroomlabs-ai/headroom/issues/4022)) ([40955b0](https://github.com/headroomlabs-ai/headroom/commit/40955b0eef2e509aad1a200db9cfa0762ca457ce))
* **learn:** decode sanitized pattern-id markers and keep visible-text dedup keys ([#3956](https://github.com/headroomlabs-ai/headroom/issues/3956)) ([ec1ba70](https://github.com/headroomlabs-ai/headroom/commit/ec1ba70c974fb0729870bfd444cdc1152a1b4301))
* **learn:** make live traffic learning use the shared error classifier ([#4110](https://github.com/headroomlabs-ai/headroom/issues/4110)) ([e6eaa41](https://github.com/headroomlabs-ai/headroom/commit/e6eaa411791750884a7eb2594d0b86f9e4100f81))
* **learn:** pin the learned verbosity level on a cache-mode proxy ([#4033](https://github.com/headroomlabs-ai/headroom/issues/4033)) ([71663b4](https://github.com/headroomlabs-ai/headroom/commit/71663b44e26fc2e0ad7d52c0b264aa7500926900))
* **logging:** add payload-safe helpers for exceptions, URLs, ids and repeat warnings ([#4138](https://github.com/headroomlabs-ai/headroom/issues/4138)) ([bebe559](https://github.com/headroomlabs-ai/headroom/commit/bebe5593ea4abaf326215c7236586b38e7b325a5))
* **onnx:** stop magika's ORT intra-op pool from spinning idle cores ([#4189](https://github.com/headroomlabs-ai/headroom/issues/4189)) ([2016dc6](https://github.com/headroomlabs-ai/headroom/commit/2016dc6d6064926790b9c843fbf1798d2e660524))
* **openclaw:** preserve tool-call thought signatures ([#4038](https://github.com/headroomlabs-ai/headroom/issues/4038)) ([37f3f9e](https://github.com/headroomlabs-ai/headroom/commit/37f3f9efe16f6b1ff94e03dbae85a27e387097a2))
* **plugins/openclaw:** keep compression system-prompt notice cache-stable ([#3811](https://github.com/headroomlabs-ai/headroom/issues/3811)) ([f885187](https://github.com/headroomlabs-ai/headroom/commit/f8851878a4feb0b64df8a5b22a89ebb198199bdf))
* **pricing:** reconcile cache billing with model-specific LiteLLM rates ([#3033](https://github.com/headroomlabs-ai/headroom/issues/3033)) ([463c1a4](https://github.com/headroomlabs-ai/headroom/commit/463c1a43e30fc33cb256a3f455daf28043e53b05))
* **providers:** drop the shadowed POST /v1/messages route spec ([#4075](https://github.com/headroomlabs-ai/headroom/issues/4075)) ([69a16cb](https://github.com/headroomlabs-ai/headroom/commit/69a16cb59c0fe4b8233caf5824e34e5772f48d81))
* **proxy/bedrock:** record the real upstream status on InvokeModel outcomes ([#4025](https://github.com/headroomlabs-ai/headroom/issues/4025)) ([159daa2](https://github.com/headroomlabs-ai/headroom/commit/159daa25a0886fb5c5808e37d62fe8cf4971290a))
* **proxy/streaming:** tolerate malformed upstream SSE events ([#2558](https://github.com/headroomlabs-ai/headroom/issues/2558)) ([d091fbd](https://github.com/headroomlabs-ai/headroom/commit/d091fbd9f2ccc522de87350c0bc7a85f0de230eb))
* **proxy:** astgrep disk verify truncation ([#3192](https://github.com/headroomlabs-ai/headroom/issues/3192)) ([1fb4cba](https://github.com/headroomlabs-ai/headroom/commit/1fb4cbaea0dcc62aa092bac3af04991d994207d0))
* **proxy:** break the compact-every-turn loop near the real context window ([#2942](https://github.com/headroomlabs-ai/headroom/issues/2942)) ([76cceeb](https://github.com/headroomlabs-ai/headroom/commit/76cceeb48728a4f179626e43f1ec23d1f7cebd79))
* **proxy:** classify failed streams as failed requests ([#3747](https://github.com/headroomlabs-ai/headroom/issues/3747)) ([42d4f58](https://github.com/headroomlabs-ai/headroom/commit/42d4f58b434bdca8f81cabf5f00d6e8e02a7fb2c))
* **proxy:** don't retry a 429/529 that cannot succeed within the backoff cap ([#3992](https://github.com/headroomlabs-ai/headroom/issues/3992)) ([a961a6f](https://github.com/headroomlabs-ai/headroom/commit/a961a6fea083a9a739df40d1371e1e7ec108516d))
* **proxy:** don't send a memory continuation with unanswered client tool calls ([#4009](https://github.com/headroomlabs-ai/headroom/issues/4009)) ([#4013](https://github.com/headroomlabs-ai/headroom/issues/4013)) ([87e05b6](https://github.com/headroomlabs-ai/headroom/commit/87e05b68b8aa578f1439abfc8006b38cd09db14d))
* **proxy:** forward x-litellm-key-* headers on streaming path ([#2532](https://github.com/headroomlabs-ai/headroom/issues/2532)) ([33ade5b](https://github.com/headroomlabs-ai/headroom/commit/33ade5b0e1019adf34d9fd888cc105d4bc23935e))
* **proxy:** ignore defer_loading when measuring a turn hook's tool delta ([#4056](https://github.com/headroomlabs-ai/headroom/issues/4056)) ([f8212a3](https://github.com/headroomlabs-ai/headroom/commit/f8212a39dcc5b03a75e98b60a8ecdef81a0f48ed))
* **proxy:** keep Claude Haiku 5.5 mid-conversation system messages in place ([#4153](https://github.com/headroomlabs-ai/headroom/issues/4153)) ([a9eb2a7](https://github.com/headroomlabs-ai/headroom/commit/a9eb2a7b6fe6b75042646284109846da46939649))
* **proxy:** keep leading Anthropic system payloads valid ([#3671](https://github.com/headroomlabs-ai/headroom/issues/3671)) ([d9e29bb](https://github.com/headroomlabs-ai/headroom/commit/d9e29bb2600a746dea80caa7721f0fb98109589c))
* **proxy:** log the savings and metrics failures that currently vanish ([#4084](https://github.com/headroomlabs-ai/headroom/issues/4084)) ([2800932](https://github.com/headroomlabs-ai/headroom/commit/2800932e1827400cf41be1cff6154f78f691ccce))
* **proxy:** read stream cache usage from message_delta; keep Fireworks sessions on one replica ([#4174](https://github.com/headroomlabs-ai/headroom/issues/4174)) ([30b22df](https://github.com/headroomlabs-ai/headroom/commit/30b22df7fda6163c576c8f720982bf1ca48762c3))
* **proxy:** record the provider's billed input count on streamed turns ([#4052](https://github.com/headroomlabs-ai/headroom/issues/4052)) ([a9815bb](https://github.com/headroomlabs-ai/headroom/commit/a9815bbb5fa2d2347ceeeac0f01cc9f041e2ded2))
* **proxy:** say why proxy.log is missing and why a knob or extension was ignored ([#4088](https://github.com/headroomlabs-ai/headroom/issues/4088)) ([72302a3](https://github.com/headroomlabs-ai/headroom/commit/72302a3998104a400765fa7e21177ed59f429f38))
* **release:** synchronize editable uv lock version ([#4054](https://github.com/headroomlabs-ai/headroom/issues/4054)) ([3f99066](https://github.com/headroomlabs-ai/headroom/commit/3f990663cca5b9dd2ed0ca26343b0619bbab0aa7))
* **router:** bound ML compression per request, not just per block ([#3721](https://github.com/headroomlabs-ai/headroom/issues/3721)) ([f37980f](https://github.com/headroomlabs-ai/headroom/commit/f37980f7f7612e7ae58b4f3b5b98f185e216fd91))
* **router:** preserve nested JSON records through compression ([#3680](https://github.com/headroomlabs-ai/headroom/issues/3680)) ([fd06703](https://github.com/headroomlabs-ai/headroom/commit/fd067033da185f1abf48ea58e63c6d71d4d11ec1))
* **savings,ccr:** log the ledger and MCP failures that are swallowed silently ([#4105](https://github.com/headroomlabs-ai/headroom/issues/4105)) ([97680e7](https://github.com/headroomlabs-ai/headroom/commit/97680e7782423308b8e35c5560fea5b1d9434e1b))
* **savings:** don't let a thin holdout arm decide the headline number ([#3127](https://github.com/headroomlabs-ai/headroom/issues/3127)) ([2a12e03](https://github.com/headroomlabs-ai/headroom/commit/2a12e035a3239bdfbb4fe75e1246923c144aabef))
* **security:** resolve 23 open CodeQL alerts ([#4045](https://github.com/headroomlabs-ai/headroom/issues/4045)) ([a88e2d5](https://github.com/headroomlabs-ai/headroom/commit/a88e2d51452f7a2fa1882639585d482e1f05d92f))
* **security:** resolve high-severity CodeQL alerts ([#4005](https://github.com/headroomlabs-ai/headroom/issues/4005)) ([dea9092](https://github.com/headroomlabs-ai/headroom/commit/dea9092e19385f286b7f67a64f4d85de2708d756))
* **smart-crusher:** preserve wrapped retrieval results in apply ([#4149](https://github.com/headroomlabs-ai/headroom/issues/4149)) ([9762a14](https://github.com/headroomlabs-ai/headroom/commit/9762a14a40bde4d3f58a027c086b6ac75fbd5ed2))
* **subscription:** log a failed OTEL window update instead of passing silently ([#4131](https://github.com/headroomlabs-ai/headroom/issues/4131)) ([7d9dd55](https://github.com/headroomlabs-ai/headroom/commit/7d9dd55e7c4bbd2a95b054de7e5722c4cf20ce50))
* **toin:** make diagnostic pattern identifiers addressable ([#4021](https://github.com/headroomlabs-ai/headroom/issues/4021)) ([def6d41](https://github.com/headroomlabs-ai/headroom/commit/def6d41185d3091d4ef42ae379829087deeaf38f))
* **transforms:** log failed transforms with tracebacks ([#3981](https://github.com/headroomlabs-ai/headroom/issues/3981)) ([a654558](https://github.com/headroomlabs-ai/headroom/commit/a65455804ce6c16670af6fe253bd9f8f6105bfe3))
* **wrap:** carry the shared proxy's extensions over to a dedicated Copilot proxy ([#4154](https://github.com/headroomlabs-ai/headroom/issues/4154)) ([feea130](https://github.com/headroomlabs-ai/headroom/commit/feea130f81953030bda222ffe88abb61fbb60ee8))
* **wrap:** let `wrap opencode` target a third-party OpenAI-compatible upstream ([#3125](https://github.com/headroomlabs-ai/headroom/issues/3125)) ([0d7d61d](https://github.com/headroomlabs-ai/headroom/commit/0d7d61d5ccaee25d399ae3209e8ce067e8673b30))
* **wrap:** reject saved bob gateway URLs the proxy would not route ([#3975](https://github.com/headroomlabs-ai/headroom/issues/3975)) ([944eafc](https://github.com/headroomlabs-ai/headroom/commit/944eafc6d4bcebbe6624cff95681f5af8b257868))
* **wrap:** trim the wrap claude startup banner ([#3900](https://github.com/headroomlabs-ai/headroom/issues/3900)) ([aba75cb](https://github.com/headroomlabs-ai/headroom/commit/aba75cbf6d2fe1e4c728e4af258907d9c28028d0))
* **wrap:** warn when reused proxy ignores compression settings ([#4019](https://github.com/headroomlabs-ai/headroom/issues/4019)) ([278bbc8](https://github.com/headroomlabs-ai/headroom/commit/278bbc8771938eec18e89df942e1594b6ddf41d4))
### Performance Improvements
* **proxy:** avoid eager dependency imports ([#3546](https://github.com/headroomlabs-ai/headroom/issues/3546)) ([59bd482](https://github.com/headroomlabs-ai/headroom/commit/59bd482fa1661293d86834e73fe90f0ee21130c5))
### Code Refactoring
* **backends:** reuse the LiteLLM tool converters in the any-llm backend ([#4076](https://github.com/headroomlabs-ai/headroom/issues/4076)) ([03538f2](https://github.com/headroomlabs-ai/headroom/commit/03538f2f2f55cafc0cec4ddf1b22e3189e2a0a24))
* **cli:** one missing-binary error for every wrap command ([#4122](https://github.com/headroomlabs-ai/headroom/issues/4122)) ([2c2357a](https://github.com/headroomlabs-ai/headroom/commit/2c2357ad342de69d4576f0e38efc58646f054913))
* **cli:** remove test-only and dead helpers from wrap, proxy and mcp ([#4118](https://github.com/headroomlabs-ai/headroom/issues/4118)) ([73f59a3](https://github.com/headroomlabs-ai/headroom/commit/73f59a32ccda8fe9de385031ccd032d1007be650))
* **compression:** deprecate the test-only UniversalCompressor package ([#4095](https://github.com/headroomlabs-ai/headroom/issues/4095)) ([fc8ff5a](https://github.com/headroomlabs-ai/headroom/commit/fc8ff5a7619271ffe306ffad50f2ee936d5d2158))
* **core:** remove unreferenced helpers, attributes and a shadowed module ([#4091](https://github.com/headroomlabs-ai/headroom/issues/4091)) ([08fce18](https://github.com/headroomlabs-ai/headroom/commit/08fce1831067005f048cb81f0033abc17a89e9fd))
* **graph:** drop the bespoke codebase-memory-mcp downloader nothing calls ([#4102](https://github.com/headroomlabs-ai/headroom/issues/4102)) ([30d23fb](https://github.com/headroomlabs-ai/headroom/commit/30d23fb799674a5d9a3c531baf09a307d62c2bf2))
* **mcp_registry:** share spec helpers and fold GrokRegistrar onto the Codex TOML registrar ([#4121](https://github.com/headroomlabs-ai/headroom/issues/4121)) ([6e14ee0](https://github.com/headroomlabs-ai/headroom/commit/6e14ee0bc2dde72378b841f708f73cdf79df6e2d))
* **memory,learn,cache:** remove unreferenced classes, methods and constants ([#4112](https://github.com/headroomlabs-ai/headroom/issues/4112)) ([abbf36f](https://github.com/headroomlabs-ai/headroom/commit/abbf36f052fca643a3cd5f7cadd21b5a7d4bf406))
* **memory:** deprecate the never-wired agent memory writers ([#4101](https://github.com/headroomlabs-ai/headroom/issues/4101)) ([2e497cb](https://github.com/headroomlabs-ai/headroom/commit/2e497cbec3c26c1d2c83adcc94794164cbab3268))
* **memory:** deprecate the orphaned Mem0SystemAdapter ([#4114](https://github.com/headroomlabs-ai/headroom/issues/4114)) ([7387b8c](https://github.com/headroomlabs-ai/headroom/commit/7387b8cc11ecdf4775faa6042e7cc15d114b4942))
* **memory:** drop the unused extraction prompts and tool schemas ([#4100](https://github.com/headroomlabs-ai/headroom/issues/4100)) ([6d23895](https://github.com/headroomlabs-ai/headroom/commit/6d23895dc003e865c3c5d4690853551406e7cdc8))
* **memory:** remove the unused memory budget manager ([#4099](https://github.com/headroomlabs-ai/headroom/issues/4099)) ([e7ac6ca](https://github.com/headroomlabs-ai/headroom/commit/e7ac6ca6f81834549a66fc0832b1ddb2470da245))
* **proxy:** delete the unused memory_tool_adapter module ([#4071](https://github.com/headroomlabs-ai/headroom/issues/4071)) ([7e5d97f](https://github.com/headroomlabs-ai/headroom/commit/7e5d97fe29073af0751cc0abc7bdf6a6d3bd74a2))
* **proxy:** drop the test-only memory ranker and file-backed native memory ops ([#4072](https://github.com/headroomlabs-ai/headroom/issues/4072)) ([fc5ac70](https://github.com/headroomlabs-ai/headroom/commit/fc5ac70b4a1eac8f49d86ad386c76c67bab40372))
* **proxy:** parse HEADROOM_OUTPUT_HOLDOUT in one place ([#4082](https://github.com/headroomlabs-ai/headroom/issues/4082)) ([1a4e419](https://github.com/headroomlabs-ai/headroom/commit/1a4e4194a0b26e4f09026c18ac6b8935c6a99c0c))
* **proxy:** remove dead aliases and wrappers from helpers, body_forwarding, forwarded_headers ([#4080](https://github.com/headroomlabs-ai/headroom/issues/4080)) ([63cc9af](https://github.com/headroomlabs-ai/headroom/commit/63cc9afa9d282aeae127e6af20d9a9efa2eebd7e))
* **proxy:** remove dead wiring and unused re-exports from server.py ([#4073](https://github.com/headroomlabs-ai/headroom/issues/4073)) ([58387c1](https://github.com/headroomlabs-ai/headroom/commit/58387c1174e6f7f526c3677b72986079da554a8a))
* **proxy:** remove test-only and dead helpers from the handlers ([#4117](https://github.com/headroomlabs-ai/headroom/issues/4117)) ([31d378b](https://github.com/headroomlabs-ai/headroom/commit/31d378b0e5337bf8c572ca272e8649762457dc5f))
* **proxy:** remove the unreachable debug branches from the Responses payload compressor ([#4116](https://github.com/headroomlabs-ai/headroom/issues/4116)) ([132cd58](https://github.com/headroomlabs-ai/headroom/commit/132cd583daeb968dd4121f0163677f5b1605f29c))
* **proxy:** remove the unreachable debug branches from the Responses unit router ([#4115](https://github.com/headroomlabs-ai/headroom/issues/4115)) ([25cc2d5](https://github.com/headroomlabs-ai/headroom/commit/25cc2d586316fee5cb67b7a25ef2927198a0ae6b))
* **proxy:** remove unreferenced and test-only helpers ([#4074](https://github.com/headroomlabs-ai/headroom/issues/4074)) ([e5cbec5](https://github.com/headroomlabs-ai/headroom/commit/e5cbec5f1a860eb51e4e49507b8eb26742abba22))
* remove test-only compatibility helpers in rollout and agent_savings ([#4089](https://github.com/headroomlabs-ai/headroom/issues/4089)) ([310c108](https://github.com/headroomlabs-ai/headroom/commit/310c108c24caef1839a538a28878b6709f8987f9))
* remove write-only and test-only code in subscription and install ([#4123](https://github.com/headroomlabs-ai/headroom/issues/4123)) ([c191bee](https://github.com/headroomlabs-ai/headroom/commit/c191beef59cc9bde622cf7db251ac94eb2a20c70))
* **transforms:** deprecate the unused Python AnchorSelector port ([#4104](https://github.com/headroomlabs-ai/headroom/issues/4104)) ([9b1971d](https://github.com/headroomlabs-ai/headroom/commit/9b1971dd82c941d683902014b203de4bf617cc61))
* **transforms:** deprecate unused compress_with_stats, extract_batch and align_for_cache ([#4098](https://github.com/headroomlabs-ai/headroom/issues/4098)) ([e4a1ec1](https://github.com/headroomlabs-ai/headroom/commit/e4a1ec19be787a312624fdca52e2184b9a4127b9))
* **transforms:** drop the Python mirror of the Rust log selector ([#4096](https://github.com/headroomlabs-ai/headroom/issues/4096)) ([a20c76c](https://github.com/headroomlabs-ai/headroom/commit/a20c76c26b15557a1bf176c4ef84f46121550297))
* **transforms:** drop the Python mirror of the Rust search selector ([#4103](https://github.com/headroomlabs-ai/headroom/issues/4103)) ([47f8710](https://github.com/headroomlabs-ai/headroom/commit/47f8710817ddc6612127662714b5fcecf83dc644))
* **transforms:** remove the unused summarize_dropped_items ([#4093](https://github.com/headroomlabs-ai/headroom/issues/4093)) ([eaa7308](https://github.com/headroomlabs-ai/headroom/commit/eaa7308a52620ad803b13c7f66300d7196f63212))
* **transforms:** remove unused convenience wrappers and helpers ([#4097](https://github.com/headroomlabs-ai/headroom/issues/4097)) ([5c72d82](https://github.com/headroomlabs-ai/headroom/commit/5c72d824f4d1ab0d46a960f8f61a14d000482591))
## [0.40.0](https://github.com/headroomlabs-ai/headroom/compare/v0.39.1...v0.40.0) (2026-10-06)
### ⚠ BREAKING CHANGES
* **proxy:** read HEADROOM_LICENSE and make usage reporting opt-in ([#3857](https://github.com/headroomlabs-ai/headroom/issues/3857))
* drop the crewai extra to remove chromadb from the lockfile ([#3870](https://github.com/headroomlabs-ai/headroom/issues/3870))
### Features
* **compress:** add per-message compression diagnostics ([#3058](https://github.com/headroomlabs-ai/headroom/issues/3058)) ([fef99cc](https://github.com/headroomlabs-ai/headroom/commit/fef99cc5b444bb16ac33fe8ec70108f7c0271de1))
* **compress:** live-agent densify mode, lossless and cache-safe ([#1402](https://github.com/headroomlabs-ai/headroom/issues/1402)) ([84f0e84](https://github.com/headroomlabs-ai/headroom/commit/84f0e84dccd3736b4a0c6c817bc83da307a5fbb8))
* **dashboard:** add CO₂ Saved card to dashboard and /stats API ([#1369](https://github.com/headroomlabs-ai/headroom/issues/1369)) ([2bc9419](https://github.com/headroomlabs-ai/headroom/commit/2bc94194671548c5def53809f736340285e20e76))
* **dashboard:** give savings metrics one canonical home ([#3320](https://github.com/headroomlabs-ai/headroom/issues/3320)) ([6af7efe](https://github.com/headroomlabs-ai/headroom/commit/6af7efe0d1fa9786d1fd5e5dc9884b7750c0f569))
* **learn:** add agy (Antigravity CLI) as an analysis backend ([#3939](https://github.com/headroomlabs-ai/headroom/issues/3939)) ([4ba231a](https://github.com/headroomlabs-ai/headroom/commit/4ba231ab3d51c409804af24ea03692aed33deb2e))
* **live-zone:** wire the SourceCode and PlainText dispatch arms ([#3227](https://github.com/headroomlabs-ai/headroom/issues/3227)) ([49f69be](https://github.com/headroomlabs-ai/headroom/commit/49f69be2836e90cbd210e39d82b36d514404cc76))
* **memory:** persist TrafficLearner pending evidence across restarts + expose learner stats ([#3104](https://github.com/headroomlabs-ai/headroom/issues/3104)) ([4257ed4](https://github.com/headroomlabs-ai/headroom/commit/4257ed4df377a93cd2e0d526ef61d2a32cbc54cf))
* **proxy:** add x-headroom-keep-last-turns header for per-request context trimming (issue [#2858](https://github.com/headroomlabs-ai/headroom/issues/2858)) ([#3059](https://github.com/headroomlabs-ai/headroom/issues/3059)) ([246162d](https://github.com/headroomlabs-ai/headroom/commit/246162d70bbc68cc1b7d44a015ddaf320cd23a3d))
* **proxy:** route Gemini plugin traffic through native transforms ([#2697](https://github.com/headroomlabs-ai/headroom/issues/2697)) ([0ad996a](https://github.com/headroomlabs-ai/headroom/commit/0ad996a82eef65183271243fa71bb0f5653be369))
* **proxy:** serve on a Unix domain socket (--uds) ([#3151](https://github.com/headroomlabs-ai/headroom/issues/3151)) ([e7b3baf](https://github.com/headroomlabs-ai/headroom/commit/e7b3baf236b832e1d4d086c4425b8d32560d0d7c))
* **wrap:** add headroom wrap bob for IBM Bob CLI ([#3801](https://github.com/headroomlabs-ai/headroom/issues/3801)) ([0b7dab4](https://github.com/headroomlabs-ai/headroom/commit/0b7dab47c62a8372c7bf7031d744658d71745679))
* **wrap:** extend reduce-at-source quiet defaults to telemetry/nag banners ([#2550](https://github.com/headroomlabs-ai/headroom/issues/2550)) ([3a3a465](https://github.com/headroomlabs-ai/headroom/commit/3a3a465bb129ad74f6e04f7c50e0fe7489383ba2))
### Bug Fixes
* **anthropic:** preserve failed CCR continuations ([#3843](https://github.com/headroomlabs-ai/headroom/issues/3843)) ([94bb055](https://github.com/headroomlabs-ai/headroom/commit/94bb055810dc1258bd248cd0a9d0e7c51df64844))
* **backends/anyllm:** map Anthropic tool_choice none to OpenAI none ([#3963](https://github.com/headroomlabs-ai/headroom/issues/3963)) ([d722a64](https://github.com/headroomlabs-ai/headroom/commit/d722a6414c3896ef092a0d8764c64d9681e07410))
* **backends/litellm:** align streaming usage tokens with the non-streaming path ([#2688](https://github.com/headroomlabs-ai/headroom/issues/2688)) ([90a68e0](https://github.com/headroomlabs-ai/headroom/commit/90a68e02910126373f3d3769158925e3a55ce411))
* **backends/litellm:** keep the upstream 4xx status on send_message errors ([#3944](https://github.com/headroomlabs-ai/headroom/issues/3944)) ([e0e41cd](https://github.com/headroomlabs-ai/headroom/commit/e0e41cd2f57a80612ddbf1568e4ad245046a0131))
* **backends/litellm:** map Anthropic tool_choice none to OpenAI none ([#2689](https://github.com/headroomlabs-ai/headroom/issues/2689)) ([57a5708](https://github.com/headroomlabs-ai/headroom/commit/57a57088de8920091ecaaac0e3cadf3932698154))
* **backends/litellm:** match the caller-key Bearer scheme case-insensitively (RFC 7235) ([#3965](https://github.com/headroomlabs-ai/headroom/issues/3965)) ([848d7a0](https://github.com/headroomlabs-ai/headroom/commit/848d7a04b489600d3c0de0ba4f7c47cdb8ed5cc2))
* **backends/litellm:** report requested model in OpenAI streaming chunks ([#2690](https://github.com/headroomlabs-ai/headroom/issues/2690)) ([8538a83](https://github.com/headroomlabs-ai/headroom/commit/8538a831531bb277a6083ed2a010312a849c3050))
* **cache:** keep prefix lineage across a replaced system tail ([#3934](https://github.com/headroomlabs-ai/headroom/issues/3934)) ([16eaec1](https://github.com/headroomlabs-ai/headroom/commit/16eaec1e95cd39135ef06f6664b309c71b03e3ad))
* **ccr:** answer headroom_retrieve on the direct chat path instead of forwarding it ([#3816](https://github.com/headroomlabs-ai/headroom/issues/3816)) ([126e144](https://github.com/headroomlabs-ai/headroom/commit/126e144876d2bd01246b5066dd5d3379b7a0e2da))
* **ccr:** inject headroom_retrieve before the prefix is warm, not after ([#3810](https://github.com/headroomlabs-ai/headroom/issues/3810)) ([bb8c285](https://github.com/headroomlabs-ai/headroom/commit/bb8c285714b19dadf4f96305ba5a74877a0dd103))
* **ccr:** only proactively expand compressions present in the requesting conversation ([#3924](https://github.com/headroomlabs-ai/headroom/issues/3924)) ([9b9a883](https://github.com/headroomlabs-ai/headroom/commit/9b9a883e96ec28e361a3d95e34ec29ecd2ef8abb))
* **ccr:** unwrap Hermes batched tool_call so headroom_retrieve stays exempt ([#3839](https://github.com/headroomlabs-ai/headroom/issues/3839)) ([2f07668](https://github.com/headroomlabs-ai/headroom/commit/2f076687b069f09c69a1ce3e6f3eaaa521b838f7))
* **ci:** clear dependency audit and gate Docker publishing ([#3984](https://github.com/headroomlabs-ai/headroom/issues/3984)) ([67ce7d0](https://github.com/headroomlabs-ai/headroom/commit/67ce7d0f3119883a873a53c1fb1e569c80d36d71))
* **ci:** keep hard watchdog out of pytest shards ([#3845](https://github.com/headroomlabs-ai/headroom/issues/3845)) ([2527431](https://github.com/headroomlabs-ai/headroom/commit/25274310ca396aaf5761d78d07106de3dfde2951))
* **ci:** tolerate missing Docker cache blobs ([#3945](https://github.com/headroomlabs-ai/headroom/issues/3945)) ([540f4da](https://github.com/headroomlabs-ai/headroom/commit/540f4da19995ce9ec60240f991a8091466ee7e51))
* clarify CCR marker content preservation ([#3175](https://github.com/headroomlabs-ai/headroom/issues/3175)) ([005a4e1](https://github.com/headroomlabs-ai/headroom/commit/005a4e146f94e2388e8e0e7eaabe5a831676b26b))
* **cli:** honor CODEX_HOME and align wrap/init/doctor with the live proxy port ([#3855](https://github.com/headroomlabs-ai/headroom/issues/3855)) ([5bf6612](https://github.com/headroomlabs-ai/headroom/commit/5bf661232667fe2573caafcd9b48f86c6388b5bd))
* **cli:** strip unmarked headroom_memory TOML table before injecting ([#3490](https://github.com/headroomlabs-ai/headroom/issues/3490)) ([08dda4c](https://github.com/headroomlabs-ai/headroom/commit/08dda4cb0b5fe69bff8aa1deeabfb2111738087c))
* **codex:** explain why wrapped Codex runs without the shared server ([#3899](https://github.com/headroomlabs-ai/headroom/issues/3899)) ([1982b3a](https://github.com/headroomlabs-ai/headroom/commit/1982b3a773093ff8262887e69ffb12e342ce4ffc))
* **codex:** preserve remote compaction in init config ([#3410](https://github.com/headroomlabs-ai/headroom/issues/3410)) ([6df4a96](https://github.com/headroomlabs-ai/headroom/commit/6df4a963ae4cfefa2269b751874e142b02feb726))
* **codex:** resolve per-turn project context ([#2636](https://github.com/headroomlabs-ai/headroom/issues/2636)) ([0396ea2](https://github.com/headroomlabs-ai/headroom/commit/0396ea2fc22d72d95d1f3bfa63bfbdd0abd74a80))
* **codex:** strip stale compression framing on the Responses subpath passthrough ([#3792](https://github.com/headroomlabs-ai/headroom/issues/3792)) ([0eba65c](https://github.com/headroomlabs-ai/headroom/commit/0eba65ca4a8f04b55d568fc35829eca053a7cfac))
* **copilot:** defer keychain auth lookup ([#2739](https://github.com/headroomlabs-ai/headroom/issues/2739)) ([81a8a28](https://github.com/headroomlabs-ai/headroom/commit/81a8a28da38f1837c6b8dd6217a35a5ebb98bc87))
* **copilot:** read timezone-naive token expiry as UTC, not host local time ([#3216](https://github.com/headroomlabs-ai/headroom/issues/3216)) ([2b2dc1b](https://github.com/headroomlabs-ai/headroom/commit/2b2dc1b2c93c596ad5129dff914978c5679ef126))
* **copilot:** warn when a VS Code profile cannot see the proxy settings ([#3919](https://github.com/headroomlabs-ai/headroom/issues/3919)) ([7b68fc2](https://github.com/headroomlabs-ai/headroom/commit/7b68fc263a925f97116e1e648cd3fa22a0f04f1b))
* **deps:** patch brace-expansion in wrap E2E lockfile ([#3873](https://github.com/headroomlabs-ai/headroom/issues/3873)) ([5e0435d](https://github.com/headroomlabs-ai/headroom/commit/5e0435d2156229c04951da9fafeafdf74d2abf84))
* **deps:** patch urllib3 and Next.js advisories ([#3896](https://github.com/headroomlabs-ai/headroom/issues/3896)) ([573e385](https://github.com/headroomlabs-ai/headroom/commit/573e385f120cfd4f5e4d54c791025f2253abf08a))
* **doctor:** recognize Azure Foundry routing for Claude Code ([#1339](https://github.com/headroomlabs-ai/headroom/issues/1339)) ([d5318ac](https://github.com/headroomlabs-ai/headroom/commit/d5318ac235595b9740fccb0910ec7139c42d51a0))
* **grok:** route CLI traffic to api.x.ai on shared proxies ([#2693](https://github.com/headroomlabs-ai/headroom/issues/2693)) ([ef1c528](https://github.com/headroomlabs-ai/headroom/commit/ef1c528e92a2b037a170f94ec8adf917322ba630))
* honor configured port in container startup and healthcheck ([#2436](https://github.com/headroomlabs-ai/headroom/issues/2436)) ([1b7977c](https://github.com/headroomlabs-ai/headroom/commit/1b7977cecd95e53cccf45f04248097a8e4137b3f))
* **install/apply:** add --no-rate-limit flag, persist in proxy_args ([#1350](https://github.com/headroomlabs-ai/headroom/issues/1350)) ([#1365](https://github.com/headroomlabs-ai/headroom/issues/1365)) ([31d0344](https://github.com/headroomlabs-ai/headroom/commit/31d03449910fbacbefdde8c04ea2c10299f9bba6))
* **install:** parse Windows Task Scheduler XML output ([#3830](https://github.com/headroomlabs-ai/headroom/issues/3830)) ([c32a4f4](https://github.com/headroomlabs-ai/headroom/commit/c32a4f4131934dee48d793156fb8a536a4b2617e))
* **install:** replace the launchd wrapper with the proxy listener ([#3224](https://github.com/headroomlabs-ai/headroom/issues/3224)) ([44db755](https://github.com/headroomlabs-ai/headroom/commit/44db755ee6d85d0eb74f1fc79ef737741f87debc))
* **install:** use safe model backends for persistent services ([#3646](https://github.com/headroomlabs-ai/headroom/issues/3646)) ([7287589](https://github.com/headroomlabs-ai/headroom/commit/7287589d23b76911b036d97f58c3cc043a9693c8))
* **integrations:** record metric timestamps in UTC, not naive local time ([#3117](https://github.com/headroomlabs-ai/headroom/issues/3117)) ([76ef2c3](https://github.com/headroomlabs-ai/headroom/commit/76ef2c3bc9cc302f4b638fab83467ab53cb192c1))
* **kompress:** degrade when a native dep is installed but unloadable ([#3133](https://github.com/headroomlabs-ai/headroom/issues/3133)) ([8f3d677](https://github.com/headroomlabs-ai/headroom/commit/8f3d677354f50df9181cbb3fa002003be4e3c237))
* **kompress:** pin ModernBERT tokenizer and encoder revisions ([#3808](https://github.com/headroomlabs-ai/headroom/issues/3808)) ([2de5828](https://github.com/headroomlabs-ai/headroom/commit/2de582875b7dd1ef8754df8a2905ab4d72dab581))
* **learn:** drop the echoed prompt from a failed cli's error ([#3928](https://github.com/headroomlabs-ai/headroom/issues/3928)) ([f00d425](https://github.com/headroomlabs-ai/headroom/commit/f00d42561402752e56666ff35962ad8da6f7966c))
* **learn:** keep CLAUDE.local.md out of git via .git/info/exclude ([#3108](https://github.com/headroomlabs-ai/headroom/issues/3108)) ([c072251](https://github.com/headroomlabs-ai/headroom/commit/c072251c10a1334265974ed33f655487518d41d0))
* **learn:** keep transcript-derived content inside the managed block ([#3850](https://github.com/headroomlabs-ai/headroom/issues/3850)) ([c46e74d](https://github.com/headroomlabs-ai/headroom/commit/c46e74d06b5ffa9643f420f28d2da6686fb7e487))
* **learn:** merge git worktree sessions into the repo's project ([#3854](https://github.com/headroomlabs-ai/headroom/issues/3854)) ([3fdf18e](https://github.com/headroomlabs-ai/headroom/commit/3fdf18ededa162e5f46f5a996a164a6ca9de283f))
* **learn:** preserve stable traffic pattern items ([#2293](https://github.com/headroomlabs-ai/headroom/issues/2293)) ([1631cde](https://github.com/headroomlabs-ai/headroom/commit/1631cde6865cbc03a60ade5e9baaa28837add4e4))
* **learn:** recognize escaped persisted pattern IDs ([#3951](https://github.com/headroomlabs-ai/headroom/issues/3951)) ([2e74f06](https://github.com/headroomlabs-ai/headroom/commit/2e74f06ecec73d365e06de6832b13f7e9fe386b7))
* **learn:** run the claude-cli analysis with hooks disabled ([#3926](https://github.com/headroomlabs-ai/headroom/issues/3926)) ([2a4d34c](https://github.com/headroomlabs-ai/headroom/commit/2a4d34c47676080336577bb4b227864258cb2c78))
* **learn:** run the claude-cli analysis with no tools ([#3892](https://github.com/headroomlabs-ai/headroom/issues/3892)) ([db90b93](https://github.com/headroomlabs-ai/headroom/commit/db90b93da9f8decb9cac7fa007674de7974a1cdb))
* **log_compressor:** keep and name pytest short-summary failures ([#3828](https://github.com/headroomlabs-ai/headroom/issues/3828)) ([d90b320](https://github.com/headroomlabs-ai/headroom/commit/d90b32008dc47f25737d9cef8da942fd8dc1af76))
* make Headroom work behind Zscaler and other TLS-inspecting networks ([#3831](https://github.com/headroomlabs-ai/headroom/issues/3831)) ([66258c4](https://github.com/headroomlabs-ai/headroom/commit/66258c40a4589bb2fef934dec6fb69c527ae8b44))
* **mcp:** bound version-detection git subprocess ([#3038](https://github.com/headroomlabs-ai/headroom/issues/3038)) ([0712e04](https://github.com/headroomlabs-ai/headroom/commit/0712e048b034e7f15ce10c0fc4e99795cab082ff))
* **mcp:** escape control characters when rendering TOML server blocks ([#3964](https://github.com/headroomlabs-ai/headroom/issues/3964)) ([a96154f](https://github.com/headroomlabs-ai/headroom/commit/a96154f03b65179f23496a1ff9682cfc476eaff5))
* **mcp:** keep other apps' tables when replacing the Codex/Grok MCP span ([#3877](https://github.com/headroomlabs-ai/headroom/issues/3877)) ([d0fd56e](https://github.com/headroomlabs-ai/headroom/commit/d0fd56e4910c997a3121aa27ab578b998b260f5a))
* **mcp:** resolve opencode.jsonc for MCP registration ([#2496](https://github.com/headroomlabs-ai/headroom/issues/2496)) ([f824a27](https://github.com/headroomlabs-ai/headroom/commit/f824a270f132516443deeef2555076bf4cd40a34))
* **memory:** align project routing with wrap headers ([#3603](https://github.com/headroomlabs-ai/headroom/issues/3603)) ([b1b005a](https://github.com/headroomlabs-ai/headroom/commit/b1b005a9a867d75cbc6b459b1f5276c272e7ac50))
* **memory:** avoid injecting tools into tool-free requests ([#3677](https://github.com/headroomlabs-ai/headroom/issues/3677)) ([46755b5](https://github.com/headroomlabs-ai/headroom/commit/46755b5f72804c32dc7d6ded5595342a2cac6157))
* **memory:** close SQLite connections in memory/fts5/graph adapters ([#3153](https://github.com/headroomlabs-ai/headroom/issues/3153)) ([231a627](https://github.com/headroomlabs-ai/headroom/commit/231a6277024938d28e0ebeda29378dea3822b527))
* **memory:** handle list-shaped system content in inline memory injection ([#3794](https://github.com/headroomlabs-ai/headroom/issues/3794)) ([717527b](https://github.com/headroomlabs-ai/headroom/commit/717527bc8681665326c064ed47e3f5a0284b01a5))
* **memory:** ignore leading cd prefix when pairing Bash error recoveries ([#3776](https://github.com/headroomlabs-ai/headroom/issues/3776)) ([143a38d](https://github.com/headroomlabs-ai/headroom/commit/143a38d56f5bddb96dd486948c3318bd8dc93372))
* **memory:** pin LF on memory writers and guard the learn-writer newline contract ([#3706](https://github.com/headroomlabs-ai/headroom/issues/3706)) ([b10dd8d](https://github.com/headroomlabs-ai/headroom/commit/b10dd8db6e71903e550edd1707ce044f3520f0b4))
* **oauth2:** mint and inject only on requests that go upstream ([#3849](https://github.com/headroomlabs-ai/headroom/issues/3849)) ([f977d52](https://github.com/headroomlabs-ai/headroom/commit/f977d525e4cf4ac1cad64dd59cfc6d3e54cd8e36))
* **offline:** make HEADROOM_OFFLINE a real air-gap via one chokepoint ([#3729](https://github.com/headroomlabs-ai/headroom/issues/3729)) ([119d1a1](https://github.com/headroomlabs-ai/headroom/commit/119d1a19393697f22140da654f0b6a10c3866d79))
* **opencode:** hide spawned Windows console windows ([#3743](https://github.com/headroomlabs-ai/headroom/issues/3743)) ([2157400](https://github.com/headroomlabs-ai/headroom/commit/2157400b005b858fb4ab96dadde022bb22d3d244))
* **opencode:** route only LLM traffic through Headroom ([#3884](https://github.com/headroomlabs-ai/headroom/issues/3884)) ([d75eecd](https://github.com/headroomlabs-ai/headroom/commit/d75eecd814d391f51c6b98b1594c0ea180e9103a))
* **output-savings:** seed the holdout key on the whole first user message ([#3209](https://github.com/headroomlabs-ai/headroom/issues/3209)) ([117ff72](https://github.com/headroomlabs-ai/headroom/commit/117ff72ec9aa6385c4e6afb23f06a4a6edb59f8e))
* **parser:** stop counting HTML comments twice in waste signals ([#3942](https://github.com/headroomlabs-ai/headroom/issues/3942)) ([d0e9c4c](https://github.com/headroomlabs-ai/headroom/commit/d0e9c4ca4810f36c8bd71cfc567be9e72c8c06d1))
* **parser:** whitespace waste signal always reported zero ([#1102](https://github.com/headroomlabs-ai/headroom/issues/1102)) ([f19bc9a](https://github.com/headroomlabs-ai/headroom/commit/f19bc9a9c344e846ef61de09652c55f8db835aa1))
* **plugin:** resolve hook CLI through plugin-root launcher ([#3053](https://github.com/headroomlabs-ai/headroom/issues/3053)) ([ef7605f](https://github.com/headroomlabs-ai/headroom/commit/ef7605fdbb82a5c1a75c9192432bc719aa92927d))
* **plugins/openclaw:** return messages the proxy did not change exactly as they came in ([#3826](https://github.com/headroomlabs-ai/headroom/issues/3826)) ([d1ad189](https://github.com/headroomlabs-ai/headroom/commit/d1ad189819d0dd87137267a17233ab2703eb803c))
* prevent HF tokenizer downloads in offline mode ([#3783](https://github.com/headroomlabs-ai/headroom/issues/3783)) ([d503c57](https://github.com/headroomlabs-ai/headroom/commit/d503c575eabd6dfed3f390754d391a337340d7d7))
* **pricing:** add Claude Sonnet 5.5 / Opus 5.5 / Fable 5.1, correct Sonnet 5 rates ([#3841](https://github.com/headroomlabs-ai/headroom/issues/3841)) ([0d99c56](https://github.com/headroomlabs-ai/headroom/commit/0d99c56dc519c4684079a0e1107399068342104d))
* protect file reads in chained shell commands ([#2668](https://github.com/headroomlabs-ai/headroom/issues/2668)) ([ffc3599](https://github.com/headroomlabs-ai/headroom/commit/ffc359976b09f64388ac9cb8685904c5a5f59708))
* **providers/vertex:** Vertex route multi-region locations ([#3802](https://github.com/headroomlabs-ai/headroom/issues/3802)) ([a9c1ac5](https://github.com/headroomlabs-ai/headroom/commit/a9c1ac5368798382b0d7e081e910a6df2a728bb0))
* **proxy/anthropic:** keep tool_result blocks first when neutralizing headroom_retrieve history ([#3874](https://github.com/headroomlabs-ai/headroom/issues/3874)) ([ccd9fff](https://github.com/headroomlabs-ai/headroom/commit/ccd9fffce93cd93d694d78c601ec50eeff0bd256))
* **proxy/batch:** honor x-headroom-bypass on the batch paths ([#2570](https://github.com/headroomlabs-ai/headroom/issues/2570)) ([9b26a49](https://github.com/headroomlabs-ai/headroom/commit/9b26a49c14eacd8e14385bf8d28c67b2425b3c5c))
* **proxy:** add same-origin check to /v1/retrieve/tool_call ([#3955](https://github.com/headroomlabs-ai/headroom/issues/3955)) ([2297b50](https://github.com/headroomlabs-ai/headroom/commit/2297b5059f27c0018b15f7857a5b3a7026a68bdd))
* **proxy:** bill the whole prompt on the gateway path so savings read true ([#3632](https://github.com/headroomlabs-ai/headroom/issues/3632)) ([befdb52](https://github.com/headroomlabs-ai/headroom/commit/befdb52fd565ff990e4ff1463f0550ba7df588b5))
* **proxy:** carry safeguard_results through SSE resynthesis ([#3958](https://github.com/headroomlabs-ai/headroom/issues/3958)) ([f37ef59](https://github.com/headroomlabs-ai/headroom/commit/f37ef591894c6b89bc25ea628b64b40bdd1037fb))
* **proxy:** classify Pi Codex Responses alias ([#2583](https://github.com/headroomlabs-ai/headroom/issues/2583)) ([a493f55](https://github.com/headroomlabs-ai/headroom/commit/a493f559a1a85a5462fc3bf3f363d64c3c9444ce))
* **proxy:** do not cache error replies delivered as http 200 ([#3930](https://github.com/headroomlabs-ai/headroom/issues/3930)) ([1132a54](https://github.com/headroomlabs-ai/headroom/commit/1132a54b21482332f6ffeeebe8c9935a69709afa))
* **proxy:** drop a tool_reference naming the search tool itself ([#3172](https://github.com/headroomlabs-ai/headroom/issues/3172)) ([b73adaa](https://github.com/headroomlabs-ai/headroom/commit/b73adaa0ce36a2e65a98f5590c46ea555751b445))
* **proxy:** F3 — per-tenant TOIN learning key ([#404](https://github.com/headroomlabs-ai/headroom/issues/404)) ([f90a56b](https://github.com/headroomlabs-ai/headroom/commit/f90a56b0388f3dcb6455425a3405b40b67da6858))
* **proxy:** forward operator-listed guarded upstreams through a proxy ([#3804](https://github.com/headroomlabs-ai/headroom/issues/3804)) ([4b7e5d2](https://github.com/headroomlabs-ai/headroom/commit/4b7e5d246e54b856af22cd1a90b47d93b26226cb))
* **proxy:** freeze and replay the forwarded prefix on Gemini paths ([#3394](https://github.com/headroomlabs-ai/headroom/issues/3394)) ([#3865](https://github.com/headroomlabs-ai/headroom/issues/3865)) ([dd84321](https://github.com/headroomlabs-ai/headroom/commit/dd84321daa0c3c9dca9264098bb396a75d9e52cd))
* **proxy:** gate the raw request body, not just its Content-Length header ([#3338](https://github.com/headroomlabs-ai/headroom/issues/3338)) ([c946b6b](https://github.com/headroomlabs-ai/headroom/commit/c946b6b0b0ae048c576940d1a57071b84cb05fb6))
* **proxy:** hard watchdog that dumps and exits when a native call seizes the GIL ([#3180](https://github.com/headroomlabs-ai/headroom/issues/3180)) ([79daeb5](https://github.com/headroomlabs-ai/headroom/commit/79daeb590f46c8f74483e975647c202d09f01fbb))
* **proxy:** inject memory context past a trailing system message ([#3948](https://github.com/headroomlabs-ai/headroom/issues/3948)) ([3948dbe](https://github.com/headroomlabs-ai/headroom/commit/3948dbe409eba48c065a3ecb2af9fa2f51921787))
* **proxy:** keep cache_control outside content blocks where the Chat Completions client put it ([#3895](https://github.com/headroomlabs-ai/headroom/issues/3895)) ([a6d6c14](https://github.com/headroomlabs-ai/headroom/commit/a6d6c14cf781a7725e4e8366e8cd86b1e4e44ba9))
* **proxy:** keep exception text and the proxy token out of client output ([#3851](https://github.com/headroomlabs-ai/headroom/issues/3851)) ([861e94d](https://github.com/headroomlabs-ai/headroom/commit/861e94d8c173bcca1ec4ae4f84a3e7ef477c4a19))
* **proxy:** keep the newest user message verbatim in cache-mode delta compression ([#3923](https://github.com/headroomlabs-ai/headroom/issues/3923)) ([613ae92](https://github.com/headroomlabs-ai/headroom/commit/613ae9215058c1d5cabc67186f3b47089b22eddb))
* **proxy:** key rate limits by peer unless the caller authenticated ([#3860](https://github.com/headroomlabs-ai/headroom/issues/3860)) ([6fb7cad](https://github.com/headroomlabs-ai/headroom/commit/6fb7cadfe4c54c2be6b90e9fdea36e91da7b2945))
* **proxy:** kill the image worker a timed-out call abandons ([#3940](https://github.com/headroomlabs-ai/headroom/issues/3940)) ([793bb85](https://github.com/headroomlabs-ai/headroom/commit/793bb85659d9aa907115ec16ea3356c5459f6299))
* **proxy:** label plain OpenAI chat traffic openai, not custom ([#3912](https://github.com/headroomlabs-ai/headroom/issues/3912)) ([7df8bd8](https://github.com/headroomlabs-ai/headroom/commit/7df8bd87b54725174e1ea88e2dcd428b66cb608f))
* **proxy:** log response_content_length in proxy_inbound_response ([#2701](https://github.com/headroomlabs-ai/headroom/issues/2701)) ([cfa479a](https://github.com/headroomlabs-ai/headroom/commit/cfa479af8e551d5d2710debf80adb86fd72b16e5))
* **proxy:** preserve Bedrock body-limit error dialect ([#3871](https://github.com/headroomlabs-ai/headroom/issues/3871)) ([ffc6edb](https://github.com/headroomlabs-ai/headroom/commit/ffc6edb4ba7a775d2f6440769b626132a66aa7d3))
* **proxy:** preserve Windows service when Rust core is blocked ([#2989](https://github.com/headroomlabs-ai/headroom/issues/2989)) ([eaa16d9](https://github.com/headroomlabs-ai/headroom/commit/eaa16d9f6343f9d5364863c7522734f6b86b1844))
* **proxy:** quarantine compression only once half the pool is stuck ([#3932](https://github.com/headroomlabs-ai/headroom/issues/3932)) ([be2b205](https://github.com/headroomlabs-ai/headroom/commit/be2b205c51430236404177bb7d80930a2d299d5a))
* **proxy:** read HEADROOM_LICENSE and make usage reporting opt-in ([#3857](https://github.com/headroomlabs-ai/headroom/issues/3857)) ([7460389](https://github.com/headroomlabs-ai/headroom/commit/746038991cf2b4dbb31dd2227d607db7bc273da7))
* **proxy:** reap wrap-spawned proxies once no wrap clients remain ([#3202](https://github.com/headroomlabs-ai/headroom/issues/3202)) ([4227bd2](https://github.com/headroomlabs-ai/headroom/commit/4227bd2419e72a922149d5dfaf416808d8e08139))
* **proxy:** redact upstream error detail and add opt-in /metrics loopback gate ([#2589](https://github.com/headroomlabs-ai/headroom/issues/2589)) ([a05717f](https://github.com/headroomlabs-ai/headroom/commit/a05717f6ec2b0514ccaa42b9bd1b3c95d3465730))
* **proxy:** refuse token-less non-loopback binds, gate operator routes ([#3852](https://github.com/headroomlabs-ai/headroom/issues/3852)) ([ee731d7](https://github.com/headroomlabs-ai/headroom/commit/ee731d7ea84503ad844eb2759fcb5bbf04a1ae0e))
* **proxy:** reset the cc-switch upstream when Claude Official is selected ([#3166](https://github.com/headroomlabs-ai/headroom/issues/3166)) ([fed7281](https://github.com/headroomlabs-ai/headroom/commit/fed7281120af5b476d3911ca1ebf4dc66d5ca1ea))
* **proxy:** run extension middleware inside the security gate and body ceiling ([#3847](https://github.com/headroomlabs-ai/headroom/issues/3847)) ([1854fd7](https://github.com/headroomlabs-ai/headroom/commit/1854fd7fd3f52bb4cc0b17803de0a04a850eb8f7))
* **proxy:** run injected memory tools server-side on streaming turns ([#3947](https://github.com/headroomlabs-ai/headroom/issues/3947)) ([1cf4966](https://github.com/headroomlabs-ai/headroom/commit/1cf496612e781ef8d67ff87ee4f78037492f0bc7))
* **proxy:** share one compression deadline across a Responses request ([#3938](https://github.com/headroomlabs-ai/headroom/issues/3938)) ([4d27d02](https://github.com/headroomlabs-ai/headroom/commit/4d27d024b09fe04f6e32b158063538f084d7febb))
* **proxy:** skip pricing lookup for passthrough:* models ([#2585](https://github.com/headroomlabs-ai/headroom/issues/2585)) ([f87848c](https://github.com/headroomlabs-ai/headroom/commit/f87848cf78db43dcd4b7e9b6aca3859245348456))
* **proxy:** stop headroom logger from suppressing propagation to stdout/stderr ([#3096](https://github.com/headroomlabs-ai/headroom/issues/3096)) ([f78e66f](https://github.com/headroomlabs-ai/headroom/commit/f78e66f7cc5e00d5db04c493f702ef4ebe7035b0))
* **relevance:** bound segment size by max_chars ([#2518](https://github.com/headroomlabs-ai/headroom/issues/2518)) ([0ef7b2a](https://github.com/headroomlabs-ai/headroom/commit/0ef7b2a7fdd7daf4dbb8628c616c28a233ce7910))
* **reporting:** price the savings tile instead of fabricating $0.00 ([#3821](https://github.com/headroomlabs-ai/headroom/issues/3821)) ([f519fa8](https://github.com/headroomlabs-ai/headroom/commit/f519fa8b97aa9ccef369f5973f1d476af2a65edf))
* **router:** fall back to built-ins when an external compressor passes through ([#3893](https://github.com/headroomlabs-ai/headroom/issues/3893)) ([2c4b20f](https://github.com/headroomlabs-ai/headroom/commit/2c4b20fcba6da0366c1c637a2a3cc61e843012a7))
* **router:** keep ccr_retrieve exemption through orchestrator wrappers ([#3915](https://github.com/headroomlabs-ai/headroom/issues/3915)) ([6151ed1](https://github.com/headroomlabs-ai/headroom/commit/6151ed1f52f3d0dd24eb28e0fa666226150a0055))
* **rust-proxy:** forward request paths verbatim and pin the rustls provider ([#3853](https://github.com/headroomlabs-ai/headroom/issues/3853)) ([9d98ea5](https://github.com/headroomlabs-ai/headroom/commit/9d98ea59082ca6b00be2508f00b85ef90c94f744))
* **savings:** record tool-schema dollars disjointly beside the folded headline ([#3170](https://github.com/headroomlabs-ai/headroom/issues/3170)) ([c719d4a](https://github.com/headroomlabs-ai/headroom/commit/c719d4af55ebca177c81c98f74531bfaca831366))
* **savings:** stop scoring unobserved strata against the global mean ([#3128](https://github.com/headroomlabs-ai/headroom/issues/3128)) ([f864525](https://github.com/headroomlabs-ai/headroom/commit/f8645257c074b7e5babd949e705d7ca4e8366ae4))
* **sdk:** keep tool names on Vercel tool-result parts through the OpenAI round trip ([#3883](https://github.com/headroomlabs-ai/headroom/issues/3883)) ([b715671](https://github.com/headroomlabs-ai/headroom/commit/b7156714acf1f06cd37f642044455e23e2f89d47))
* **sdk:** preserve Gemini media parts in message conversion instead of dropping the turn ([#3882](https://github.com/headroomlabs-ai/headroom/issues/3882)) ([038c923](https://github.com/headroomlabs-ai/headroom/commit/038c923b4bcd01305f18d993e301b837d668c343))
* **sdk:** stop JSON-wrapping structured tool_result content in the Anthropic adapter ([#3797](https://github.com/headroomlabs-ai/headroom/issues/3797)) ([2e4a60a](https://github.com/headroomlabs-ai/headroom/commit/2e4a60ae3730fc7ea8f5afebbc29961d5fd0af11))
* **search:** stop a context line's body from becoming its line marker ([#3788](https://github.com/headroomlabs-ai/headroom/issues/3788)) ([f3f2e00](https://github.com/headroomlabs-ai/headroom/commit/f3f2e0077ae67d492bfc5922e9a49427036e32e0))
* **security:** create memory stores and other state files owner-only ([#3848](https://github.com/headroomlabs-ai/headroom/issues/3848)) ([5119b6e](https://github.com/headroomlabs-ai/headroom/commit/5119b6eb545e35b617e2d08b183e968d0104d548))
* **security:** exempt only GET health probes from the proxy token ([#3921](https://github.com/headroomlabs-ai/headroom/issues/3921)) ([d99779d](https://github.com/headroomlabs-ai/headroom/commit/d99779dae69d44c934d2115ffd8ee1f1a6cbb898))
* **security:** partition the response cache by credential and principal ([#3862](https://github.com/headroomlabs-ai/headroom/issues/3862)) ([ee6cfcc](https://github.com/headroomlabs-ai/headroom/commit/ee6cfcccf6a8944225344c2a468f509783934239))
* **security:** poll usage only with the operator's own credential ([#3863](https://github.com/headroomlabs-ai/headroom/issues/3863)) ([65e63c0](https://github.com/headroomlabs-ai/headroom/commit/65e63c08835410149bec4acba8e3737366eb0586))
* **security:** stop forwarding the proxy token to upstream providers ([#3891](https://github.com/headroomlabs-ai/headroom/issues/3891)) ([0147cf0](https://github.com/headroomlabs-ai/headroom/commit/0147cf02207fd76be8a14932bcc65a9709bfdb59))
* **settings:** report live proxy configuration ([#3177](https://github.com/headroomlabs-ai/headroom/issues/3177)) ([58b1454](https://github.com/headroomlabs-ai/headroom/commit/58b1454282f2b2dee49616c6637fa135ccb885b7))
* **smart-crusher:** recurse at adaptive array limit ([#3770](https://github.com/headroomlabs-ai/headroom/issues/3770)) ([7790bde](https://github.com/headroomlabs-ai/headroom/commit/7790bdeebda290b9fdbf899df1cbf9a05e0bc5e9))
* **storage:** page JSONL queries after sorting ([#3872](https://github.com/headroomlabs-ai/headroom/issues/3872)) ([91237ca](https://github.com/headroomlabs-ai/headroom/commit/91237cae70771e8e19cbc06ca65d328ac6cb0878))
* **subscription:** match the Bearer scheme case-insensitively for the Codex usage poll (RFC 7235) ([#3966](https://github.com/headroomlabs-ai/headroom/issues/3966)) ([fe88461](https://github.com/headroomlabs-ai/headroom/commit/fe884612c07d2e8a4454615ccc5b6d4feed1d7dd))
* **subscription:** poll with the refreshed credentials-file OAuth token ([#3916](https://github.com/headroomlabs-ai/headroom/issues/3916)) ([2dc9fc2](https://github.com/headroomlabs-ai/headroom/commit/2dc9fc22f09ec85d8e73c916e7c1f6f565d271ec))
* surface Codex responses traffic in dashboard ([#399](https://github.com/headroomlabs-ai/headroom/issues/399)) ([ecc4967](https://github.com/headroomlabs-ai/headroom/commit/ecc496709b7f2c2657de25d1e3f8de3f226b32e5))
* **telemetry:** label custom-base chat upstreams from a fixed provider set ([#3759](https://github.com/headroomlabs-ai/headroom/issues/3759)) ([f0ec2bb](https://github.com/headroomlabs-ai/headroom/commit/f0ec2bb37697b1addccb416bd626e7bf3c5ea835))
* **thinking:** don't read the model's date suffix as its minor version ([#3791](https://github.com/headroomlabs-ai/headroom/issues/3791)) ([afaaaa8](https://github.com/headroomlabs-ai/headroom/commit/afaaaa88049357bac7ec186ea33678f406d02609))
* **transforms/kompress:** preserve line boundaries and tabular output in Kompress ([#3119](https://github.com/headroomlabs-ai/headroom/issues/3119)) ([fe2ed2b](https://github.com/headroomlabs-ai/headroom/commit/fe2ed2b545e4b3c97d21872232d5446cb54aedc2))
* **transforms:** judge a Codex exec envelope read by its output ([#3878](https://github.com/headroomlabs-ai/headroom/issues/3878)) ([922924e](https://github.com/headroomlabs-ai/headroom/commit/922924ef44ebd7501ff00923cc0c2007f06cfade))
* **transforms:** judge the code_aware Kompress fallback in tokens ([#3881](https://github.com/headroomlabs-ai/headroom/issues/3881)) ([6326965](https://github.com/headroomlabs-ai/headroom/commit/63269650462c1a565c259cfe3fc3bd67ac942f5a))
* **transforms:** keep record-bearing JSON out of Kompress ([#3673](https://github.com/headroomlabs-ai/headroom/issues/3673)) ([#3880](https://github.com/headroomlabs-ai/headroom/issues/3880)) ([8dbbd1d](https://github.com/headroomlabs-ai/headroom/commit/8dbbd1d8967f719acfaa21e2c1668e9f3193dbe8))
* **wrap:** never reuse a non-Headroom listener on the proxy port ([#3799](https://github.com/headroomlabs-ai/headroom/issues/3799)) ([3ffa57e](https://github.com/headroomlabs-ai/headroom/commit/3ffa57ec25a6f05dff073c0ad0b14c90ce264fd8))
* **wrap:** never reuse a proxy with incompatible routing config ([#3201](https://github.com/headroomlabs-ai/headroom/issues/3201)) ([f69e246](https://github.com/headroomlabs-ai/headroom/commit/f69e2463a0c29cea7943af5efe4b2a2170a1e863))
* **wrap:** preserve pre-set ANTHROPIC_BASE_URL as proxy upstream ([#1358](https://github.com/headroomlabs-ai/headroom/issues/1358)) ([bb1ab6a](https://github.com/headroomlabs-ai/headroom/commit/bb1ab6afd35a5c22b6c11b549aba4075fb7791ec))
* **wrap:** scope Serena's MCP registration to the wrapped project ([#2787](https://github.com/headroomlabs-ai/headroom/issues/2787)) ([#2992](https://github.com/headroomlabs-ai/headroom/issues/2992)) ([8cfeb69](https://github.com/headroomlabs-ai/headroom/commit/8cfeb692ca0cad9598160020a144c5c671cd2fc3))
* **wrap:** set ANTHROPIC_HOST so `wrap goose` actually proxies Anthropic ([#2619](https://github.com/headroomlabs-ai/headroom/issues/2619)) ([c07fad0](https://github.com/headroomlabs-ai/headroom/commit/c07fad0f37d44b7f6886e6ce774d424463636242))
* **wrap:** strip -dev from running proxy version in restart check ([#3200](https://github.com/headroomlabs-ai/headroom/issues/3200)) ([bd0296b](https://github.com/headroomlabs-ai/headroom/commit/bd0296b5e7b62b620df7b37b41ce573d57958e71))
### Performance Improvements
* add savings audit output ([#1211](https://github.com/headroomlabs-ai/headroom/issues/1211)) ([9a72bc0](https://github.com/headroomlabs-ai/headroom/commit/9a72bc024263e2470626fae7f20430db682e0042))
* **compression/code:** avoid a UTF-8 copy per code block in byte-to-char mapping ([#3169](https://github.com/headroomlabs-ai/headroom/issues/3169)) ([d5e5534](https://github.com/headroomlabs-ai/headroom/commit/d5e5534b4763b14d7710908153e0d6a89423eea9))
* **image:** OCR and SigLIP each image once, not once per turn ([#3941](https://github.com/headroomlabs-ai/headroom/issues/3941)) ([a8561fb](https://github.com/headroomlabs-ai/headroom/commit/a8561fb4be1bdc17bf8bf86ac97c17651e2820b7))
* **memory:** bound traffic-learner _persisted_ids with the dedup window ([#3341](https://github.com/headroomlabs-ai/headroom/issues/3341)) ([7e73438](https://github.com/headroomlabs-ai/headroom/commit/7e73438dc5f923c90ad0c1f2f07cb6de221c9f08))
* **metrics:** cap inbound request-path cardinality to bound memory ([#3340](https://github.com/headroomlabs-ai/headroom/issues/3340)) ([88a1f4e](https://github.com/headroomlabs-ai/headroom/commit/88a1f4e52ba220b5ddb34d94ac0a201391c16027))
* **proxy:** lighter request path: alias the message snapshot, keep the token cache on re-counts, decompress off the event loop ([#3909](https://github.com/headroomlabs-ai/headroom/issues/3909)) ([c873d13](https://github.com/headroomlabs-ai/headroom/commit/c873d13fe07d09be71d5dcbfd640a78ec5b3f0d7))
* **tokenizer:** memoize OpenAI token counts like the Anthropic counter ([#3168](https://github.com/headroomlabs-ai/headroom/issues/3168)) ([0a2c80d](https://github.com/headroomlabs-ai/headroom/commit/0a2c80d5207642a5e58ba9eb65e19cd004018642))
### Dependencies
* bump pyjwt 2.13.0 -> 2.15.1 for CVE-2026-102274 ([#3861](https://github.com/headroomlabs-ai/headroom/issues/3861)) ([37b9c46](https://github.com/headroomlabs-ai/headroom/commit/37b9c46069f11a2b2a477ae4ef25dd33bf359684))
* Bump source-map-js from 1.2.1 to 1.2.2 in /docs ([#3986](https://github.com/headroomlabs-ai/headroom/issues/3986)) ([e06631a](https://github.com/headroomlabs-ai/headroom/commit/e06631a7a78d18432c90cfb44b30e461424cfd30))
* Bump source-map-js from 1.2.1 to 1.2.2 in /plugins/openclaw ([#3988](https://github.com/headroomlabs-ai/headroom/issues/3988)) ([4be83b3](https://github.com/headroomlabs-ai/headroom/commit/4be83b35e683df077b11af4c4b37b301c4a65547))
* Bump source-map-js from 1.2.1 to 1.2.2 in /plugins/opencode ([#3987](https://github.com/headroomlabs-ai/headroom/issues/3987)) ([478dd9e](https://github.com/headroomlabs-ai/headroom/commit/478dd9e0a34cd592fdc0e313019297bc23b17db3))
* Bump source-map-js from 1.2.1 to 1.2.2 in /sdk/typescript ([#3985](https://github.com/headroomlabs-ai/headroom/issues/3985)) ([62cde35](https://github.com/headroomlabs-ai/headroom/commit/62cde35b939d7405735b72d1e50aa7c1407e5892))
* bump the npm-minor-patch group across 2 directories with 11 updates ([#3903](https://github.com/headroomlabs-ai/headroom/issues/3903)) ([afe4f4e](https://github.com/headroomlabs-ai/headroom/commit/afe4f4eca58977ae9382dfb2899a8097b46c0909))
* bump the npm-minor-patch group across 3 directories with 11 updates ([#3910](https://github.com/headroomlabs-ai/headroom/issues/3910)) ([ff1a0d6](https://github.com/headroomlabs-ai/headroom/commit/ff1a0d69f4a83f7c5583a7af2d2961025587801e))
* bump webpki-roots from 0.26.11 to 1.0.8 ([#3905](https://github.com/headroomlabs-ai/headroom/issues/3905)) ([fee53b4](https://github.com/headroomlabs-ai/headroom/commit/fee53b4daa3a0ac2b2378a692278f24f0062d584))
* drop the crewai extra to remove chromadb from the lockfile ([#3870](https://github.com/headroomlabs-ai/headroom/issues/3870)) ([59b8cef](https://github.com/headroomlabs-ai/headroom/commit/59b8cefc24e48539974787e0677298f335b2720e))
### Code Refactoring
* **ccr:** read the expansion query through extract_user_query ([#2707](https://github.com/headroomlabs-ai/headroom/issues/2707)) ([dcec845](https://github.com/headroomlabs-ai/headroom/commit/dcec845851d8202ce3361022a14b3716fdeb59c0))
* **wrap:** generate goose/openhands/openclaude from a WrapTarget registry ([#3800](https://github.com/headroomlabs-ai/headroom/issues/3800)) ([de4cf7e](https://github.com/headroomlabs-ai/headroom/commit/de4cf7e7a1ece51ce6c60d25bc34f46897e972c9))
## [0.39.1](https://github.com/headroomlabs-ai/headroom/compare/v0.39.0...v0.39.1) (2026-09-26)
### Bug Fixes
* **proxy:** stop the 0.39.0 TPM limiter from refusing large-context requests forever ([#3806](https://github.com/headroomlabs-ai/headroom/issues/3806)) ([7968122](https://github.com/headroomlabs-ai/headroom/commit/7968122658c31c06ef3e5b1fe7911c8cb0a79ade))
## [0.39.0](https://github.com/headroomlabs-ai/headroom/compare/v0.38.0...v0.39.0) (2026-09-25)
### Features
* **compression:** describe what CCR compression dropped, not just how much ([#3635](https://github.com/headroomlabs-ai/headroom/issues/3635)) ([62d1cc0](https://github.com/headroomlabs-ai/headroom/commit/62d1cc08b10c3e397875d82a33e500ce9a6b44e7))
* **hooks:** add protect_messages, a hard per-message compression veto ([#3772](https://github.com/headroomlabs-ai/headroom/issues/3772)) ([d17ac6a](https://github.com/headroomlabs-ai/headroom/commit/d17ac6a174d9617951ca6eff4646da4c19f83922))
* **opencode:** exclude hosts from transport plugin routing ([#3668](https://github.com/headroomlabs-ai/headroom/issues/3668)) ([0024b57](https://github.com/headroomlabs-ai/headroom/commit/0024b57405ee0b9b622c7ef5e18bde1657d4a142))
* **proxy:** let /transformations/feed omit message bodies for number-only pollers ([#3672](https://github.com/headroomlabs-ai/headroom/issues/3672)) ([46ac52d](https://github.com/headroomlabs-ai/headroom/commit/46ac52d39d6d7fc275dc24c7788bca5acfbcde31))
* **savings:** carry exact cache-read cost in history rollups ([#3734](https://github.com/headroomlabs-ai/headroom/issues/3734)) ([1cb779e](https://github.com/headroomlabs-ai/headroom/commit/1cb779e1bcaebad4cba113bf2106bcd9825bef40))
* **savings:** show the new-input savings basis beside the whole-wire figure ([#3485](https://github.com/headroomlabs-ai/headroom/issues/3485)) ([e92cccc](https://github.com/headroomlabs-ai/headroom/commit/e92cccca00fa53f27d4a04b5ec244cc105e60caa))
* **savings:** track lifetime output spend so a bill-share rate has a denominator ([#3520](https://github.com/headroomlabs-ai/headroom/issues/3520)) ([c766bdb](https://github.com/headroomlabs-ai/headroom/commit/c766bdb2b36199dedb081963a74a77652e633c98))
* **sdk:** support per-call config override in compress() ([#3370](https://github.com/headroomlabs-ai/headroom/issues/3370)) ([c3e8a1e](https://github.com/headroomlabs-ai/headroom/commit/c3e8a1ee63f8a2fec25a2f1b507413dd1f50faf7))
* **wrap:** support 1m context in vscode claude ([#3361](https://github.com/headroomlabs-ai/headroom/issues/3361)) ([fc5a09e](https://github.com/headroomlabs-ai/headroom/commit/fc5a09e1b3daa9e434b27f5f3160f8d1d56a4896))
### Bug Fixes
* **anthropic:** reject ping-only SSE from buffered CCR ([#3682](https://github.com/headroomlabs-ai/headroom/issues/3682)) ([000fefc](https://github.com/headroomlabs-ai/headroom/commit/000fefceaa26223ee95e8f9deb58bfc1854275ec))
* **anthropic:** stop the spurious compaction warning and drop dead handler code ([#3678](https://github.com/headroomlabs-ai/headroom/issues/3678)) ([6e71267](https://github.com/headroomlabs-ai/headroom/commit/6e712672cb5cc298772c8edd0e4480da53853f99))
* **backends/litellm:** stop dropping image blocks from /v1/messages requests ([#3753](https://github.com/headroomlabs-ai/headroom/issues/3753)) ([577336d](https://github.com/headroomlabs-ai/headroom/commit/577336d2b66ab0d08cd28c408e2244dca15a3bbc))
* **binaries:** fail closed when a download carries no sha256 pin ([#3724](https://github.com/headroomlabs-ai/headroom/issues/3724)) ([26a2c49](https://github.com/headroomlabs-ai/headroom/commit/26a2c4939c408bf6a0b7b20f3671378fc5cd61f6))
* **cache/google:** tolerate timezone-aware cache expiry timestamps ([#3210](https://github.com/headroomlabs-ai/headroom/issues/3210)) ([7ce2580](https://github.com/headroomlabs-ai/headroom/commit/7ce2580ff95c5943d9e68e2d1d6cd89e1abd9bdc))
* **cache:** default CCR payload previews off; harden the log when they are on ([#3728](https://github.com/headroomlabs-ai/headroom/issues/3728)) ([5cb87bc](https://github.com/headroomlabs-ai/headroom/commit/5cb87bc3516fc7c1a2ba6bde8aa6a0337c6437c9))
* **cache:** never batch-compress already-forwarded small Responses outputs in cache mode ([#3756](https://github.com/headroomlabs-ai/headroom/issues/3756)) ([ab62b9e](https://github.com/headroomlabs-ai/headroom/commit/ab62b9e0ad95494793b91c6317e122ebc8d18709))
* **cache:** preserve cache_control schema properties ([#3348](https://github.com/headroomlabs-ai/headroom/issues/3348)) ([b84c4c9](https://github.com/headroomlabs-ai/headroom/commit/b84c4c9f7164fae8e1e74e419af026ad37c2869e))
* **cache:** preserve the forwarded OpenAI chat prefix across turns ([#3757](https://github.com/headroomlabs-ai/headroom/issues/3757)) ([deca575](https://github.com/headroomlabs-ai/headroom/commit/deca575c63ec2c09b3e465229c2cd674b29299d9))
* **cache:** stop prefix transforms from busting the provider cache ([#3735](https://github.com/headroomlabs-ai/headroom/issues/3735)) ([a2bf5ed](https://github.com/headroomlabs-ai/headroom/commit/a2bf5ed1ba456303173d35611e3844909a2614db))
* **cache:** stop skipping tool compaction on a pinned tools array ([#3750](https://github.com/headroomlabs-ai/headroom/issues/3750)) ([a6a9cef](https://github.com/headroomlabs-ai/headroom/commit/a6a9cef9458e2e07c8222d76714e540a7de68ac4))
* **cli:** keep non-ASCII working directory names out of the init profile slug ([#3718](https://github.com/headroomlabs-ai/headroom/issues/3718)) ([f3d95ee](https://github.com/headroomlabs-ai/headroom/commit/f3d95ee275a33631d37f03b16a8c64c87787a064))
* **cli:** report anonymous beacon status accurately in the banner, log, and /stats ([#3533](https://github.com/headroomlabs-ai/headroom/issues/3533)) ([fa9edb3](https://github.com/headroomlabs-ai/headroom/commit/fa9edb3a2989a06323c1471131c8570425e45497))
* **content_detector:** detect CMTrace (SCCM/Intune) logs as BUILD_OUTPUT ([#3712](https://github.com/headroomlabs-ai/headroom/issues/3712)) ([6feb1fb](https://github.com/headroomlabs-ai/headroom/commit/6feb1fb22a3977f173d115285468e9ec1e8af39f))
* **dashboard:** separate rolling cache economics by owner ([#3319](https://github.com/headroomlabs-ai/headroom/issues/3319)) ([a29162b](https://github.com/headroomlabs-ai/headroom/commit/a29162baa674f3c210d074c1f0d1a0b589538b7d)), closes [#960](https://github.com/headroomlabs-ai/headroom/issues/960)
* **docker:** support OpenCode in native wrapper ([#3547](https://github.com/headroomlabs-ai/headroom/issues/3547)) ([d90dadf](https://github.com/headroomlabs-ai/headroom/commit/d90dadf2668ac3b4f9706d45aa04b39f9dabac79))
* fall back for non-admin Windows task installs ([#3437](https://github.com/headroomlabs-ai/headroom/issues/3437)) ([b958509](https://github.com/headroomlabs-ai/headroom/commit/b95850945270678bd1a1ed555149dc45be8e878e))
* **graph:** fetch and extract the zip codebase-memory-mcp asset on Windows ([#3730](https://github.com/headroomlabs-ai/headroom/issues/3730)) ([b776983](https://github.com/headroomlabs-ai/headroom/commit/b7769831282a5e67ec3a331f26e77d823decdeb6))
* **grok:** preserve xAI model context metadata ([#3312](https://github.com/headroomlabs-ai/headroom/issues/3312)) ([#3315](https://github.com/headroomlabs-ai/headroom/issues/3315)) ([c81378c](https://github.com/headroomlabs-ai/headroom/commit/c81378c878121d6bcf144c89ba8c07029e86baea))
* **init:** raise the ensure hook's timeout above cold-start latency ([#3438](https://github.com/headroomlabs-ai/headroom/issues/3438)) ([9a11109](https://github.com/headroomlabs-ai/headroom/commit/9a1110997a1387394844993a07a3674a8a09f288))
* **install:** apply managed env vars added after a deployment was installed ([#3740](https://github.com/headroomlabs-ai/headroom/issues/3740)) ([a4cb2bc](https://github.com/headroomlabs-ai/headroom/commit/a4cb2bc02144d4bb6d8213c71f66ee039d03ae15))
* **install:** wait for the old process to stop before restarting ([#3670](https://github.com/headroomlabs-ai/headroom/issues/3670)) ([11c7320](https://github.com/headroomlabs-ai/headroom/commit/11c7320bbcc45033238a7a804aaf515ea276bfed))
* **kompress:** bound the inference deadline to the request, not each block ([#3693](https://github.com/headroomlabs-ai/headroom/issues/3693)) ([7f2766c](https://github.com/headroomlabs-ai/headroom/commit/7f2766ca4beb9270ce35aa4f18aa01ef7ae3698a))
* **kompress:** keep the boolean connectives that hold a condition together ([#3687](https://github.com/headroomlabs-ai/headroom/issues/3687)) ([bf290ba](https://github.com/headroomlabs-ai/headroom/commit/bf290ba9a9de3a6af62fe3aa4bd8dacc8d9e2b92))
* **learn:** treat an unreadable project memory dir as absent instead of crashing ([#3710](https://github.com/headroomlabs-ai/headroom/issues/3710)) ([ff60d57](https://github.com/headroomlabs-ai/headroom/commit/ff60d5764c6499fe6453a475a6f26647fd87a508))
* **mcp:** accept an empty install ledger instead of failing mutations as malformed ([#3235](https://github.com/headroomlabs-ai/headroom/issues/3235)) ([19ddfe1](https://github.com/headroomlabs-ai/headroom/commit/19ddfe1a56ec7cbd48e595686f650e1d57469e4e))
* **memory/graph:** apply relation_type filter to both sides of a BOTH subgraph query ([#3236](https://github.com/headroomlabs-ai/headroom/issues/3236)) ([1a6f941](https://github.com/headroomlabs-ai/headroom/commit/1a6f941908038c696987a3f1a159f64e3145fae0))
* **memory:** fail closed for unresolved tools ([#3655](https://github.com/headroomlabs-ai/headroom/issues/3655)) ([7c3cbc8](https://github.com/headroomlabs-ai/headroom/commit/7c3cbc824c1b584274450a90ea406072faa94f61))
* **memory:** make extract_system_prompt concatenative, not first-match ([#3644](https://github.com/headroomlabs-ai/headroom/issues/3644)) ([3f3cf19](https://github.com/headroomlabs-ai/headroom/commit/3f3cf19e1a68313e949a3dd178aed2fafa050ed6))
* **memory:** tolerate None message content in inline memory parser ([#3211](https://github.com/headroomlabs-ai/headroom/issues/3211)) ([5ccec67](https://github.com/headroomlabs-ai/headroom/commit/5ccec67f0c3abfe57d52308ccbe1f93cb772eba4))
* **metrics:** split rate-limited by source and label failures by provider ([#3707](https://github.com/headroomlabs-ai/headroom/issues/3707)) ([5ff4ea1](https://github.com/headroomlabs-ai/headroom/commit/5ff4ea1ef948563304c9e8f4b9ccff0e2ae3aedd))
* **openclaw:** declare transcriptSemantics and implement commitTurn ([#3442](https://github.com/headroomlabs-ai/headroom/issues/3442)) ([a28dd4e](https://github.com/headroomlabs-ai/headroom/commit/a28dd4eab70a8fd6f72e3752e4cf1e363fca344c))
* **perf:** make budget checks constant-time ([#3368](https://github.com/headroomlabs-ai/headroom/issues/3368)) ([ed08069](https://github.com/headroomlabs-ai/headroom/commit/ed08069ba00d5335d39c1726b95b218ef55be919))
* **perf:** make rate limiter bucket checks constant-time ([#3373](https://github.com/headroomlabs-ai/headroom/issues/3373)) ([a8bd9be](https://github.com/headroomlabs-ai/headroom/commit/a8bd9becb300ea5fe774a27d89ee8d84033186da))
* preserve null and empty strings in lossless CSV compaction ([#3665](https://github.com/headroomlabs-ai/headroom/issues/3665)) ([7ad9f80](https://github.com/headroomlabs-ai/headroom/commit/7ad9f809fa1b4191937dea1c2e1a974eee2eefe8))
* **proxy:** admit container host gateway on compress routes ([#3715](https://github.com/headroomlabs-ai/headroom/issues/3715)) ([a8ae0a6](https://github.com/headroomlabs-ai/headroom/commit/a8ae0a6fd5d6274c0eb9fa63ba57f24de05c1080))
* **proxy:** bound request-log message payloads to the feed window; trim glibc too ([#3717](https://github.com/headroomlabs-ai/headroom/issues/3717)) ([994a89f](https://github.com/headroomlabs-ai/headroom/commit/994a89f169d436f369ca97824c5518287669803a))
* **proxy:** count a ceiling-stopped stream exactly instead of estimating its text ([#3771](https://github.com/headroomlabs-ai/headroom/issues/3771)) ([b36e59a](https://github.com/headroomlabs-ai/headroom/commit/b36e59a89370f2ffddcd0cfc4068956da1248626))
* **proxy:** discard partial SSE tails during finalization ([#3411](https://github.com/headroomlabs-ai/headroom/issues/3411)) ([6c0e817](https://github.com/headroomlabs-ai/headroom/commit/6c0e817bcc0a83e23a7030c3df6d313280bcb30a))
* **proxy:** enforce configured TPM limits ([#3350](https://github.com/headroomlabs-ai/headroom/issues/3350)) ([138736c](https://github.com/headroomlabs-ai/headroom/commit/138736c96f2421dbf40bf0698bc2ae8d9527a80e))
* **proxy:** fall back when forced Kompress is cold ([#3381](https://github.com/headroomlabs-ai/headroom/issues/3381)) ([ca54c2a](https://github.com/headroomlabs-ai/headroom/commit/ca54c2aba1809f9b19acfc2ef9a9dd13276f4f19))
* **proxy:** make the output shaper actually reduce output in the default mode ([#3773](https://github.com/headroomlabs-ai/headroom/issues/3773)) ([c029298](https://github.com/headroomlabs-ai/headroom/commit/c02929846cafa4b9bc68c9d2ef47f41a10a6989d))
* **proxy:** partition response cache by upstream ([#3349](https://github.com/headroomlabs-ai/headroom/issues/3349)) ([dfdc725](https://github.com/headroomlabs-ai/headroom/commit/dfdc72511ef4dd7c1ddb1e6acf1735f1ba10d2e3))
* **proxy:** pin the validated address so DNS rebinding cannot move an upstream ([#3731](https://github.com/headroomlabs-ai/headroom/issues/3731)) ([a102e05](https://github.com/headroomlabs-ai/headroom/commit/a102e05b511297ba979963a506318ca7459e63e0))
* **proxy:** preserve Claude Code auto-mode protocol ([#3784](https://github.com/headroomlabs-ai/headroom/issues/3784)) ([12c1579](https://github.com/headroomlabs-ai/headroom/commit/12c157966f3ec378d66c764757d5d55dfb2a16d1))
* **proxy:** preserve empty transport error context ([#3675](https://github.com/headroomlabs-ai/headroom/issues/3675)) ([ca02f28](https://github.com/headroomlabs-ai/headroom/commit/ca02f28c674473e94e3089eda970c046dd6a2426))
* **proxy:** preserve OpenCode Headroom retrieve results ([#3782](https://github.com/headroomlabs-ai/headroom/issues/3782)) ([c7ebaed](https://github.com/headroomlabs-ai/headroom/commit/c7ebaedd74b2146f41e1b86e27b46334df477ea2))
* **proxy:** protect Codex exec reads whose argument is a JavaScript object literal ([#3737](https://github.com/headroomlabs-ai/headroom/issues/3737)) ([ecb5e5a](https://github.com/headroomlabs-ai/headroom/commit/ecb5e5afea15493d43aa89db67a4e9e90de6cab1))
* **proxy:** reject Anthropic batch operations on Copilot ([#3318](https://github.com/headroomlabs-ai/headroom/issues/3318)) ([871bbde](https://github.com/headroomlabs-ai/headroom/commit/871bbde37ae2bf181917a281efcbc6e6a99fb1e3))
* **proxy:** repair client-side tool_search tool_reference blocks ([#3443](https://github.com/headroomlabs-ai/headroom/issues/3443)) ([f12e3fb](https://github.com/headroomlabs-ai/headroom/commit/f12e3fbeed523d2f3f81fc83c8a08b46fdc9111b))
* **proxy:** resolve Codex custom_tool_call names for Responses tool exclusion ([#3755](https://github.com/headroomlabs-ai/headroom/issues/3755)) ([55c78de](https://github.com/headroomlabs-ai/headroom/commit/55c78deaa8171234e705b4315fdde5df0156cbdb))
* **proxy:** restrict urlopen SSL context ALPN to http/1.1 ([#3567](https://github.com/headroomlabs-ai/headroom/issues/3567)) ([5baa439](https://github.com/headroomlabs-ai/headroom/commit/5baa439ebf4aae37358f7f0a5707912d1007dbbc))
* **proxy:** scope OpenAI rate limits by api-key ([#3365](https://github.com/headroomlabs-ai/headroom/issues/3365)) ([b9e8462](https://github.com/headroomlabs-ai/headroom/commit/b9e8462a3a84af7c92fa288fd53bd2e0d46b2dd2))
* **proxy:** stamp x-headroom-* compression metrics on streaming responses ([#3769](https://github.com/headroomlabs-ai/headroom/issues/3769)) ([2c4dc44](https://github.com/headroomlabs-ai/headroom/commit/2c4dc446279ddaf89930e54385a2a27fc3aa20e0))
* remove deprecated Apache license classifier ([#3566](https://github.com/headroomlabs-ai/headroom/issues/3566)) ([b2d9275](https://github.com/headroomlabs-ai/headroom/commit/b2d927532895d37721d54039a8a9d02a909cf09a))
* **savings:** report negative savings instead of flooring them at zero ([#3744](https://github.com/headroomlabs-ai/headroom/issues/3744)) ([1455f00](https://github.com/headroomlabs-ai/headroom/commit/1455f0022220f9c526e20f9898e4d56d951ec379))
* **sdk:** enforce dormant public type tests ([#3424](https://github.com/headroomlabs-ai/headroom/issues/3424)) ([95cbbb8](https://github.com/headroomlabs-ai/headroom/commit/95cbbb8158292cbdf04eb873c9e62f25946f77a2))
* **sdk:** preserve Anthropic image blocks in message conversion instead of dropping the turn ([#3439](https://github.com/headroomlabs-ai/headroom/issues/3439)) ([63676e6](https://github.com/headroomlabs-ai/headroom/commit/63676e6cff020047687af9c526c69ff1e135931d))
* **sdk:** preserve proxy authentication alongside provider credentials ([#3450](https://github.com/headroomlabs-ai/headroom/issues/3450)) ([ca4b47a](https://github.com/headroomlabs-ai/headroom/commit/ca4b47a3fc63584bcbc8792da9b099435b430c67))
* **security:** create credential files private instead of narrowing after write ([#3215](https://github.com/headroomlabs-ai/headroom/issues/3215)) ([9b8cae8](https://github.com/headroomlabs-ai/headroom/commit/9b8cae844808ec67d43006e6785daa4c246d5dfb))
* **security:** reject unauthenticated public proxy binds ([#3316](https://github.com/headroomlabs-ai/headroom/issues/3316)) ([b0c19a2](https://github.com/headroomlabs-ai/headroom/commit/b0c19a25f0e2adfd23031d5f0a37d842618c3203))
* **smart-crusher:** disclose dropped scalar-array items with a retrievable ccr sentinel ([#3692](https://github.com/headroomlabs-ai/headroom/issues/3692)) ([c1fc84a](https://github.com/headroomlabs-ai/headroom/commit/c1fc84ade6c80486b63d5e8220c08d90cb8938e6))
* **spreadsheet:** stop .xls integer rendering fabricating digits above 2^53 ([#3704](https://github.com/headroomlabs-ai/headroom/issues/3704)) ([e8a5109](https://github.com/headroomlabs-ai/headroom/commit/e8a510982a1e9164b6c2c48e92eeade90dc24fcf))
* **spreadsheet:** stop inventing digits for .xls cells above 2**53 ([#3700](https://github.com/headroomlabs-ai/headroom/issues/3700)) ([1a7c5bb](https://github.com/headroomlabs-ai/headroom/commit/1a7c5bbf52aefb4ce950f6b4c8e7feac0c62315e))
* **tests:** ask litellm for a model it prices instead of naming a retired one ([#3722](https://github.com/headroomlabs-ai/headroom/issues/3722)) ([0ad5e68](https://github.com/headroomlabs-ai/headroom/commit/0ad5e68ca559b3fc2c82a230a577b1b4bfc77792))
* **tool-search:** detect every wire shape of client-side deferral ([#3746](https://github.com/headroomlabs-ai/headroom/issues/3746)) ([665b73d](https://github.com/headroomlabs-ai/headroom/commit/665b73df1b256c4eb0c41e44e29c93211e35f5d4))
* **tool-search:** don't orphan deferred tools, and stop overstating the saving ([#3739](https://github.com/headroomlabs-ai/headroom/issues/3739)) ([85f9e01](https://github.com/headroomlabs-ai/headroom/commit/85f9e01d71c712ef071d64a54e3e1c57eb330147))
* **tool-search:** make the core-tools override authoritative and the warning recurrent ([#3745](https://github.com/headroomlabs-ai/headroom/issues/3745)) ([a9757c9](https://github.com/headroomlabs-ai/headroom/commit/a9757c9c7e0e50635c5bc82d59a543cc45cde7b2))
* **transforms:** detect fixed-width command output as tabular and keep it out of Kompress ([#3786](https://github.com/headroomlabs-ai/headroom/issues/3786)) ([6c9aef1](https://github.com/headroomlabs-ai/headroom/commit/6c9aef1dec71e99fa2872737de9842ce9fea284d))
* **transforms:** stop embedded JSON pre-pass short-circuiting HTML extraction ([#3620](https://github.com/headroomlabs-ai/headroom/issues/3620)) ([195910b](https://github.com/headroomlabs-ai/headroom/commit/195910b218da26a053b22101df119f4cb2889813))
* **transforms:** stop routing timestamped log rows as grep matches ([#3748](https://github.com/headroomlabs-ai/headroom/issues/3748)) ([d971f7c](https://github.com/headroomlabs-ai/headroom/commit/d971f7c3983b05653ef1eb88539bbbbc3667eb67))
* **wrap:** handle SIGHUP on the shared proxy paths, not just `claude` ([#3331](https://github.com/headroomlabs-ai/headroom/issues/3331)) ([c4df2dd](https://github.com/headroomlabs-ai/headroom/commit/c4df2dde62d0c8d527323b4f6985d57469ae594e))
* **wrap:** stop blocking the launch on the Serena pre-index ([#3557](https://github.com/headroomlabs-ai/headroom/issues/3557)) ([df8ebdf](https://github.com/headroomlabs-ai/headroom/commit/df8ebdf97da68496ab514f321583a393b74243ea))
### Performance Improvements
* **cache:** drop eager full-backend TTL sweep on every new-key store() ([#3256](https://github.com/headroomlabs-ai/headroom/issues/3256)) ([2fed685](https://github.com/headroomlabs-ai/headroom/commit/2fed685e77734efe234cc12da363d185d7922378))
* **cache:** LRU-bound the compression-feedback tool-pattern map ([#3342](https://github.com/headroomlabs-ai/headroom/issues/3342)) ([2d10b10](https://github.com/headroomlabs-ai/headroom/commit/2d10b10ae47aa10682d94d7145b7b6204c2a9f70))
* **memory:** reindex FTS5 a page at a time instead of a record at a time ([#3466](https://github.com/headroomlabs-ai/headroom/issues/3466)) ([3e36aef](https://github.com/headroomlabs-ai/headroom/commit/3e36aefb432e69e7ce065c1efe7600f85909e7fc))
* **providers:** cache Google/Cohere token counters across requests ([#3273](https://github.com/headroomlabs-ai/headroom/issues/3273)) ([cc6a07c](https://github.com/headroomlabs-ai/headroom/commit/cc6a07cd651abbd7552814414e90096e0c1bcdde))
* **relevance:** order BM25 query terms once, not once per document ([#3468](https://github.com/headroomlabs-ai/headroom/issues/3468)) ([6880984](https://github.com/headroomlabs-ai/headroom/commit/6880984b4a96d29fd655354e7633b797c9f511b6))
### Dependencies
* bump dotenv from 17.4.2 to 18.0.1 in /sdk/typescript ([#3765](https://github.com/headroomlabs-ai/headroom/issues/3765)) ([56edfbc](https://github.com/headroomlabs-ai/headroom/commit/56edfbc9312b3e16a505c5d82e9ce7d75ffb8a76))
* bump ruff from 0.16.7 to 0.16.8 in the pip-minor-patch group ([#3761](https://github.com/headroomlabs-ai/headroom/issues/3761)) ([b9ded1a](https://github.com/headroomlabs-ai/headroom/commit/b9ded1ae5587751cfd10dd2254d73f7205ca58a2))
* bump the cargo-minor-patch group with 3 updates ([#3762](https://github.com/headroomlabs-ai/headroom/issues/3762)) ([fbbe8b8](https://github.com/headroomlabs-ai/headroom/commit/fbbe8b8e99635fd9805b7ef7946fa00d615ab0a9))
* bump the npm-minor-patch group across 2 directories with 19 updates ([#3763](https://github.com/headroomlabs-ai/headroom/issues/3763)) ([54357ff](https://github.com/headroomlabs-ai/headroom/commit/54357ff660a413dafa01594c54362de6e11ebb9f))
* bump the npm-minor-patch group across 3 directories with 9 updates ([#3764](https://github.com/headroomlabs-ai/headroom/issues/3764)) ([6311332](https://github.com/headroomlabs-ai/headroom/commit/63113329cfe96dde5087fe0a2837eb543ed1391b))
### Code Refactoring
* **sdk:** route _fetch through rawFetch instead of duplicating it ([#3473](https://github.com/headroomlabs-ai/headroom/issues/3473)) ([b2b5847](https://github.com/headroomlabs-ai/headroom/commit/b2b58474c4a3b43bbcc81cc833c0a8f28dadaa21))
* **smart-crusher:** drop the dead crush_object clone from the object path ([#3705](https://github.com/headroomlabs-ai/headroom/issues/3705)) ([7221724](https://github.com/headroomlabs-ai/headroom/commit/72217242c1cc52e3ed09780b53440abe9ca22478))
## [0.38.0](https://github.com/headroomlabs-ai/headroom/compare/v0.37.0...v0.38.0) (2026-09-21)
### Features
* **beacon:** schema v2 — routing/compression training signal, gzip transport ([#3253](https://github.com/headroomlabs-ai/headroom/issues/3253)) ([67eb910](https://github.com/headroomlabs-ai/headroom/commit/67eb910e38b9879bb0bcbacdc36db69e36901075))
* **cache:** add the headroom-cache-ttl offline TTL estimator the docs reference ([#2670](https://github.com/headroomlabs-ai/headroom/issues/2670)) ([52c7aa2](https://github.com/headroomlabs-ai/headroom/commit/52c7aa2e6faa9ff5010c84d73fa35936288bbe8a))
* **dashboard:** Cost Saved headline card; label per-row savings as message-only ([#3353](https://github.com/headroomlabs-ai/headroom/issues/3353)) ([17b0412](https://github.com/headroomlabs-ai/headroom/commit/17b041235480654ee69d775e38f2f09ffe468e1d))
* **dashboard:** show routing savings for this session and all time ([#3362](https://github.com/headroomlabs-ai/headroom/issues/3362)) ([a811984](https://github.com/headroomlabs-ai/headroom/commit/a811984ffb62a866274dda2928f78922101c824b))
* **proxy/model-router:** add require_tools route condition ([#2362](https://github.com/headroomlabs-ai/headroom/issues/2362)) ([ae75ca4](https://github.com/headroomlabs-ai/headroom/commit/ae75ca49a0af04ae03903a4136483f289962dc22))
* **proxy:** accept the OpenAI Responses shape on the gateway turn ([#3661](https://github.com/headroomlabs-ai/headroom/issues/3661)) ([be00a79](https://github.com/headroomlabs-ai/headroom/commit/be00a798c34495e9f84cfbe7c76c02ad20ede978))
* **proxy:** full-savings cost card, cache-aware tool-schema pricing, routing-stats seam ([#3351](https://github.com/headroomlabs-ai/headroom/issues/3351)) ([b8fa3ad](https://github.com/headroomlabs-ai/headroom/commit/b8fa3ad9bdf77061fe808578fba302941ab4e51e))
* **router:** elide dense machine-generated lines no compressor can shrink ([#3685](https://github.com/headroomlabs-ai/headroom/issues/3685)) ([9263b42](https://github.com/headroomlabs-ai/headroom/commit/9263b4209938986df5583c5d7c2f7795cca584a6))
* **vertex:** add Gemini 3.8 Flash agent benchmark suite ([#3371](https://github.com/headroomlabs-ai/headroom/issues/3371)) ([e67b3c8](https://github.com/headroomlabs-ai/headroom/commit/e67b3c8a29443a60d6b0018fb22f525c5cd7e709))
### Bug Fixes
* attach stdin for docker-native MCP stdio ([#3447](https://github.com/headroomlabs-ai/headroom/issues/3447)) ([a490bba](https://github.com/headroomlabs-ai/headroom/commit/a490bba83fdf20b0ddee183e6af64244a0cddb38))
* **auth:** match the Bearer auth scheme case-insensitively (RFC 7235) ([#3219](https://github.com/headroomlabs-ai/headroom/issues/3219)) ([75105e2](https://github.com/headroomlabs-ai/headroom/commit/75105e23b43a6ca156e1cbe9ab7ec9358a0c0d76))
* **cache:** keep cached-prefix replay after background recompression ([#3380](https://github.com/headroomlabs-ai/headroom/issues/3380)) ([aebe989](https://github.com/headroomlabs-ai/headroom/commit/aebe98954ee33ee9da96985cbf0f046b2f49ce22))
* **ccr:** log the exception type when a CCR continuation call fails ([#3137](https://github.com/headroomlabs-ai/headroom/issues/3137)) ([9f75f91](https://github.com/headroomlabs-ai/headroom/commit/9f75f91dc566128914cb4f14e9950a98264603cd))
* **changelog-gen:** raise on git failure and remove unreachable fallback regex ([#1247](https://github.com/headroomlabs-ai/headroom/issues/1247)) ([4e1f776](https://github.com/headroomlabs-ai/headroom/commit/4e1f7769d7b899bad25c89841b79113d3362e84e))
* **compression:** compress cache_control blocks in the request's final message ([#3483](https://github.com/headroomlabs-ai/headroom/issues/3483)) ([55d7e64](https://github.com/headroomlabs-ai/headroom/commit/55d7e647e957b0255241d843eeeac6e5e7e06382))
* **compression:** pause AST compression per language after repeated invalid-syntax discards ([#3387](https://github.com/headroomlabs-ai/headroom/issues/3387)) ([dde83c9](https://github.com/headroomlabs-ai/headroom/commit/dde83c914687a272ed5d5b8e2a04095b3d157f2f))
* **compression:** preserve Bash control flow ([#3425](https://github.com/headroomlabs-ai/headroom/issues/3425)) ([ee90207](https://github.com/headroomlabs-ai/headroom/commit/ee902074a04d691434a3485eea4428732058f159))
* **compression:** protect Bash before the tree-sitter guard, not after ([#3435](https://github.com/headroomlabs-ai/headroom/issues/3435)) ([ee6f9db](https://github.com/headroomlabs-ai/headroom/commit/ee6f9db25b9e9ab08a97de9c33b4bba8d9c55924))
* **dashboard:** make every control keyboard operable and name icon-only controls ([#3434](https://github.com/headroomlabs-ai/headroom/issues/3434)) ([15debbe](https://github.com/headroomlabs-ai/headroom/commit/15debbef7f17c8960d6d82dfffedaba4291c057d))
* **dashboard:** report Headroom-attributable cost savings, not the provider cache discount ([#3356](https://github.com/headroomlabs-ai/headroom/issues/3356)) ([bfe3c78](https://github.com/headroomlabs-ai/headroom/commit/bfe3c7873f93d281ca55316d42faa2262d946a2c))
* **deps:** bump anyio to 4.14.2 for CVE-2026-63374 and CVE-2026-64847 ([#3662](https://github.com/headroomlabs-ai/headroom/issues/3662)) ([bc21c93](https://github.com/headroomlabs-ai/headroom/commit/bc21c9370793f7e4aa94ac4c5d9a67a8d2dd0df9))
* **deps:** install on Python 3.14 from prebuilt wheels only ([#3631](https://github.com/headroomlabs-ai/headroom/issues/3631)) ([b8b222f](https://github.com/headroomlabs-ai/headroom/commit/b8b222f9403878efe08376eac71a626caf1920d6))
* **deps:** remediate vulnerable CLI and plugin dependency trees ([#3521](https://github.com/headroomlabs-ai/headroom/issues/3521)) ([4263da1](https://github.com/headroomlabs-ai/headroom/commit/4263da12b585387d87a922e34c6101ae5e5dd0aa))
* **deps:** upgrade rustls to 0.23.45 for RUSTSEC-2026-0285 ([#3584](https://github.com/headroomlabs-ai/headroom/issues/3584)) ([b256d25](https://github.com/headroomlabs-ai/headroom/commit/b256d254c06421e9d43493007ef20ea31bae2b9b))
* **doctor:** detect Codex routing via active provider base_url ([#2618](https://github.com/headroomlabs-ai/headroom/issues/2618)) ([4794d68](https://github.com/headroomlabs-ai/headroom/commit/4794d688a96b1d1442662f163d2b579f08aa030a))
* **e2e:** lock CLI dependencies for reproducible wrap builds ([#3512](https://github.com/headroomlabs-ai/headroom/issues/3512)) ([5abcdbd](https://github.com/headroomlabs-ai/headroom/commit/5abcdbd041a680c42a4df482eab62f2e0e8ee7fa))
* fix security issue in server.py ([#3593](https://github.com/headroomlabs-ai/headroom/issues/3593)) ([97aa949](https://github.com/headroomlabs-ai/headroom/commit/97aa949924fa6d8d0f008efa47589351e9f10004))
* hold Cursor's read_file byte-exact too ([d02e7df](https://github.com/headroomlabs-ai/headroom/commit/d02e7df5889b3f2dcd229ddfb6ca397ab3987b84))
* keep dashboard route boundaries out of upstream passthrough ([#3324](https://github.com/headroomlabs-ai/headroom/issues/3324)) ([213b371](https://github.com/headroomlabs-ai/headroom/commit/213b37158fb9fa7287d7d5884c7df43800821995))
* keep file-read tool output byte-exact through the lossless fold ([59499f7](https://github.com/headroomlabs-ai/headroom/commit/59499f73ac49b45b7bbe75da018f2eea50e14d5a))
* **kompress:** append the CCR marker whenever the saving pays for it ([#3484](https://github.com/headroomlabs-ai/headroom/issues/3484)) ([7bd4dba](https://github.com/headroomlabs-ai/headroom/commit/7bd4dbaf8f40d00f579f1cfca4bc56716f508d85))
* **kompress:** bound download retry backoff before overflow ([#3630](https://github.com/headroomlabs-ai/headroom/issues/3630)) ([a7858fd](https://github.com/headroomlabs-ai/headroom/commit/a7858fd2ae022cbd9c4373dcea124e358072730d))
* **langchain:** implement get_metrics() on HeadroomChatModel ([#3446](https://github.com/headroomlabs-ai/headroom/issues/3446)) ([#3459](https://github.com/headroomlabs-ai/headroom/issues/3459)) ([dba5d2f](https://github.com/headroomlabs-ai/headroom/commit/dba5d2f1e7b0abf65bce5c0ce2e9275857e11a18))
* **langchain:** make the integration work on LangChain 1.x, and document it ([#3399](https://github.com/headroomlabs-ai/headroom/issues/3399)) ([5d025f7](https://github.com/headroomlabs-ai/headroom/commit/5d025f7a03870a402918e6425ca9fcd40400edb2))
* **learn:** count each tool call once per tool_call_id when detecting loops ([#3462](https://github.com/headroomlabs-ai/headroom/issues/3462)) ([4088a65](https://github.com/headroomlabs-ai/headroom/commit/4088a65bb7bc9ef8aa1bf4cb59c3da8cecef4820))
* **learn:** derive loop signature from tool input identity, not display summary ([#3461](https://github.com/headroomlabs-ai/headroom/issues/3461)) ([f6b9fc0](https://github.com/headroomlabs-ai/headroom/commit/f6b9fc09e33ad091f1cf14dd60285965167d4c85))
* **learn:** distinguish Grep and Glob searches by path ([#3455](https://github.com/headroomlabs-ai/headroom/issues/3455)) ([f302a38](https://github.com/headroomlabs-ai/headroom/commit/f302a38e8fed6d45a3fb3a07ada97043a9a00dd4))
* **learn:** echo live progress during claude-cli analysis ([#3158](https://github.com/headroomlabs-ai/headroom/issues/3158)) ([4c6bd3e](https://github.com/headroomlabs-ai/headroom/commit/4c6bd3e8fc13d5b7b73092a6db775c6e6a1a69df))
* **learn:** guard session-derived path checks against PermissionError in gemini/grok plugins ([#2522](https://github.com/headroomlabs-ai/headroom/issues/2522)) ([60bfe8b](https://github.com/headroomlabs-ai/headroom/commit/60bfe8be9356217c4d5e493e10ec9cfdbe0bf716))
* **learn:** prevent Windows CRLF accumulation in context writers ([#3594](https://github.com/headroomlabs-ai/headroom/issues/3594)) ([3c1a901](https://github.com/headroomlabs-ai/headroom/commit/3c1a901572e0be14401419a9ad37e1eff40a8ae1))
* **learn:** prevent Windows CRLF accumulation in context writers ([#3594](https://github.com/headroomlabs-ai/headroom/issues/3594)) ([abde3e6](https://github.com/headroomlabs-ai/headroom/commit/abde3e6e70a6800f87fff1d961d72fd45975e1c1))
* **learn:** retry LLM analysis with a smaller digest when the prompt overflows the context window ([#3404](https://github.com/headroomlabs-ai/headroom/issues/3404)) ([d329a04](https://github.com/headroomlabs-ai/headroom/commit/d329a04b4b553a66a3a566a92a1510919cb688f3))
* **learn:** show both ends of CLI output on a parse failure ([#3517](https://github.com/headroomlabs-ai/headroom/issues/3517)) ([cb3ab61](https://github.com/headroomlabs-ai/headroom/commit/cb3ab61d4d57fa04208b8cde75f56a32cae048c8))
* **litellm:** preserve Anthropic thinking blocks; fix OpenAI-in reasoning passthrough ([#3586](https://github.com/headroomlabs-ai/headroom/issues/3586)) ([9f32800](https://github.com/headroomlabs-ai/headroom/commit/9f32800b86ad277201c2a2ce75192534f8e94b03))
* **mcp:** report a plugin-provided Serena that reconcile cannot see ([#3578](https://github.com/headroomlabs-ai/headroom/issues/3578)) ([35b1156](https://github.com/headroomlabs-ai/headroom/commit/35b11564c6217c358094732618d21eb74503aa47))
* **memory:** honor project root override for Anthropic CCR ([#3606](https://github.com/headroomlabs-ai/headroom/issues/3606)) ([91fd58d](https://github.com/headroomlabs-ai/headroom/commit/91fd58d1df37443690292115476001d7fa141bfc))
* never grep-fold timestamped logs, size-weight savings, warn on no-op model limits ([#3419](https://github.com/headroomlabs-ai/headroom/issues/3419)) ([73a6edb](https://github.com/headroomlabs-ai/headroom/commit/73a6edbe83af716bb833da5d902dd55afa6dab40))
* **openclaw:** delegate native compaction ([#2304](https://github.com/headroomlabs-ai/headroom/issues/2304)) ([eb4da64](https://github.com/headroomlabs-ai/headroom/commit/eb4da64774049261b07da2d5ebfc13f2a8b61070))
* **output-savings:** count conversations, not requests, in the holdout gate ([#3460](https://github.com/headroomlabs-ai/headroom/issues/3460)) ([53631ad](https://github.com/headroomlabs-ai/headroom/commit/53631adb15310ef7d6e257414b24733d99b2c9ca))
* **perf:** a bad savings row must not take down the whole report ([7b3d226](https://github.com/headroomlabs-ai/headroom/commit/7b3d226598fec88b5766bcf171cdd7f2a5d1cd3b))
* preserve JSON object fields in SmartCrusher ([#3648](https://github.com/headroomlabs-ai/headroom/issues/3648)) ([545f544](https://github.com/headroomlabs-ai/headroom/commit/545f54414703e9ba044efd8aa7e9005896c76ea8))
* **pricing:** price savings against the cache mix, not flat list price ([#3699](https://github.com/headroomlabs-ai/headroom/issues/3699)) ([89a58fd](https://github.com/headroomlabs-ai/headroom/commit/89a58fd1526ba158a1614c35e455e1af0a7033c0))
* protect Cursor's read_file in the core, not only in the plugin ([e23e739](https://github.com/headroomlabs-ai/headroom/commit/e23e73943bb636e89d8b9884286db4b17dea4ce4))
* **proxy/memory:** fail open when backend init errors instead of 500ing the request ([#3257](https://github.com/headroomlabs-ai/headroom/issues/3257)) ([3eba2d6](https://github.com/headroomlabs-ai/headroom/commit/3eba2d606647ece6e82366afeb1ed3e2ab99c47b))
* **proxy/openai:** keep /v1/responses savings triple coherent when schema savings exceed message tokens ([#3106](https://github.com/headroomlabs-ai/headroom/issues/3106)) ([7278b5c](https://github.com/headroomlabs-ai/headroom/commit/7278b5cbf83ff83c444eb2ffdf82790af2eb9fc0))
* **proxy:** bound decompressed request bodies to close a zip-bomb DoS ([#3325](https://github.com/headroomlabs-ai/headroom/issues/3325)) ([25a4e71](https://github.com/headroomlabs-ai/headroom/commit/25a4e71b295f4bc7e50a7fd87379c1e25436c980))
* **proxy:** enforce budget limits on OpenAI and Gemini routes ([#3579](https://github.com/headroomlabs-ai/headroom/issues/3579)) ([f734c57](https://github.com/headroomlabs-ai/headroom/commit/f734c5734123126e60770d66dc0cf0ac23f1fd27))
* **proxy:** gateway turn contract for /v1/compress behind a compress-turn seam ([#3605](https://github.com/headroomlabs-ai/headroom/issues/3605)) ([d9757dc](https://github.com/headroomlabs-ai/headroom/commit/d9757dcc6b693a02d484b1695d5821f7dc8ff6f0))
* **proxy:** gateway turn fixes found by benchmarking behind a gateway ([#3619](https://github.com/headroomlabs-ai/headroom/issues/3619)) ([aceff2e](https://github.com/headroomlabs-ai/headroom/commit/aceff2ea9dbd09a9660eca930358db27322c5763))
* **proxy:** honor compression controls for Anthropic auxiliary passes ([#3400](https://github.com/headroomlabs-ai/headroom/issues/3400)) ([fb79055](https://github.com/headroomlabs-ai/headroom/commit/fb79055b3639db32790e5b559ad3190cbaf9f6f7))
* **proxy:** keep json_bloat waste signals out of the catch-all lifetime bucket ([#3430](https://github.com/headroomlabs-ai/headroom/issues/3430)) ([e59cf10](https://github.com/headroomlabs-ai/headroom/commit/e59cf1012a2b277689555833fd221a92279f777d))
* **proxy:** keep non text blocks in place when relocating system sections ([#3553](https://github.com/headroomlabs-ai/headroom/issues/3553)) ([964671d](https://github.com/headroomlabs-ai/headroom/commit/964671d883e51e33ec6b6a0c1ba88335816401f5))
* **proxy:** keep OpenCode Zen /responses requests streaming ([#3659](https://github.com/headroomlabs-ai/headroom/issues/3659)) ([6f404de](https://github.com/headroomlabs-ai/headroom/commit/6f404de54e3a3822713219328b732cec031094c2))
* **proxy:** prefer explicit proxy auth header ([#3422](https://github.com/headroomlabs-ai/headroom/issues/3422)) ([f3965f7](https://github.com/headroomlabs-ai/headroom/commit/f3965f7c59ce10720bf7a0e5f26e8641ff4cca59))
* **proxy:** protect Codex exec file reads on the Responses path ([#3621](https://github.com/headroomlabs-ai/headroom/issues/3621)) ([2c56a1b](https://github.com/headroomlabs-ai/headroom/commit/2c56a1b3a7b991a42858543f6086e0a4936dbf2b))
* **proxy:** record streaming upstream 5xx as failed instead of success ([#2682](https://github.com/headroomlabs-ai/headroom/issues/2682)) ([4949cd5](https://github.com/headroomlabs-ai/headroom/commit/4949cd5594f4e13a00f7dd6bf13fa4f9d8e21575))
* **proxy:** repair tool-search history in place so signed thinking blocks keep their coordinates ([#3457](https://github.com/headroomlabs-ai/headroom/issues/3457)) ([68359c0](https://github.com/headroomlabs-ai/headroom/commit/68359c056cc9964dd0d0add39d1c8e93e7ea0027))
* **proxy:** stop get_recent deep-copying dropped message payloads ([#3613](https://github.com/headroomlabs-ai/headroom/issues/3613)) ([44b8e7b](https://github.com/headroomlabs-ai/headroom/commit/44b8e7ba877a5b01e4e1fcc91a5cb74a18e78392))
* **proxy:** support Codex Live HTTP call creation ([#3464](https://github.com/headroomlabs-ai/headroom/issues/3464)) ([53982ae](https://github.com/headroomlabs-ai/headroom/commit/53982aefb8014211d13324ad897875a2f80139b5))
* **proxy:** write per-port proxy logs so concurrent instances stop truncating each other ([#3204](https://github.com/headroomlabs-ai/headroom/issues/3204)) ([3d3c629](https://github.com/headroomlabs-ai/headroom/commit/3d3c629a9f349ed0f89102e32599aacea32e0b16))
* **read-maturation:** book matured Read savings once, not on every replay ([#3414](https://github.com/headroomlabs-ai/headroom/issues/3414)) ([85f58a9](https://github.com/headroomlabs-ai/headroom/commit/85f58a9a7a64b4120fd95ac1d2b107348206908a))
* **release:** use Node 24 for npm packaging and publishing ([#3516](https://github.com/headroomlabs-ai/headroom/issues/3516)) ([aab500b](https://github.com/headroomlabs-ai/headroom/commit/aab500b8c5286787d6c112299b8ec458f6de3c55))
* **route_advice:** per-inbound-protocol native providers (enable OpenAI-in → Claude-out) ([#3585](https://github.com/headroomlabs-ai/headroom/issues/3585)) ([dc28413](https://github.com/headroomlabs-ai/headroom/commit/dc28413fd9ab538970cc3497d37dda2d1ec8f7a4))
* **savings:** count compression savings once per conversation, not once per turn ([#3480](https://github.com/headroomlabs-ai/headroom/issues/3480)) ([427fa76](https://github.com/headroomlabs-ai/headroom/commit/427fa76f60802d1048d7686f791f12c57206e14c))
* **sdk:** emit the final SSE event when the stream has no trailing newline ([#3581](https://github.com/headroomlabs-ai/headroom/issues/3581)) ([ebc0b36](https://github.com/headroomlabs-ai/headroom/commit/ebc0b363e40efc5c72c4fef1f29b59ed729df1f8))
* serialize PyTorch device transfers with Kompress execution ([#3601](https://github.com/headroomlabs-ai/headroom/issues/3601)) ([3dfa7da](https://github.com/headroomlabs-ai/headroom/commit/3dfa7daadbabfc60707b695c1d992066dc71a41b))
* **shaper:** measure output-token steering, and stop claiming savings we did not measure ([#3377](https://github.com/headroomlabs-ai/headroom/issues/3377)) ([1390d89](https://github.com/headroomlabs-ai/headroom/commit/1390d897155e69f8b4554eed5641c2e523860d0f))
* **spreadsheet:** render an .xls cell the way the .xlsx loader renders it ([#3616](https://github.com/headroomlabs-ai/headroom/issues/3616)) ([261796f](https://github.com/headroomlabs-ai/headroom/commit/261796f9beb1634fe7175070c924a5c4fe4ed558))
* stabilize release checks and consolidate dependency updates ([#3531](https://github.com/headroomlabs-ai/headroom/issues/3531)) ([04cdf79](https://github.com/headroomlabs-ai/headroom/commit/04cdf79ab0a8423d88148ba63e960ac6b4007b9c))
* **stats:** gate the output-shaping claim on the shaper being active ([#3386](https://github.com/headroomlabs-ai/headroom/issues/3386)) ([074f0ae](https://github.com/headroomlabs-ai/headroom/commit/074f0ae9df50abc15a5ec10d05f57d165436f664))
* **stats:** stop rejected upstream turns from feeding the savings funnel ([#3615](https://github.com/headroomlabs-ai/headroom/issues/3615)) ([85fac8c](https://github.com/headroomlabs-ai/headroom/commit/85fac8c3a9bdf022c372f52758b368316d9567b7))
* **storage:** parse absolute Windows paths from URLs ([#3475](https://github.com/headroomlabs-ai/headroom/issues/3475)) ([db5ed58](https://github.com/headroomlabs-ai/headroom/commit/db5ed5822a34b16a813eb5e544cbe8d1f0435eb1))
* **tabular:** pass a table through when one cell is past the csv field limit ([#3618](https://github.com/headroomlabs-ai/headroom/issues/3618)) ([334317d](https://github.com/headroomlabs-ai/headroom/commit/334317db5d383f91133aea71b9a57a820eac088c))
* **tests:** isolate persisted settings from developer state ([#3449](https://github.com/headroomlabs-ai/headroom/issues/3449)) ([0d99e55](https://github.com/headroomlabs-ai/headroom/commit/0d99e5595de2eaf3a0642b17c0370230c8055e7d))
* **tokenizers:** estimate replayed thinking from text and signature size ([#3482](https://github.com/headroomlabs-ai/headroom/issues/3482)) ([9ed95c3](https://github.com/headroomlabs-ai/headroom/commit/9ed95c3806432e2b8df8849e60077535d6c1b3a8))
* **transforms:** classify grep -A/-B/-C context lines as search results ([#3599](https://github.com/headroomlabs-ai/headroom/issues/3599)) ([f085c47](https://github.com/headroomlabs-ai/headroom/commit/f085c4740296298860ed95f5edf8950d29ea206c))
* **transforms:** isolate ContentRouter per-request runtime state across concurrent requests ([#3556](https://github.com/headroomlabs-ai/headroom/issues/3556)) ([0bef398](https://github.com/headroomlabs-ai/headroom/commit/0bef3981107a13aa3b0c1f8b018766e3c3965337))
### Performance Improvements
* **cache:** purge expired CCR rows by deadline instead of decoding every payload ([#3465](https://github.com/headroomlabs-ai/headroom/issues/3465)) ([389e45c](https://github.com/headroomlabs-ai/headroom/commit/389e45cdde3b8c95f300469c012062d22dbdd437))
* **ccr:** bound retrieval history with a deque instead of reslicing ([#3471](https://github.com/headroomlabs-ai/headroom/issues/3471)) ([3169935](https://github.com/headroomlabs-ai/headroom/commit/316993585854c001b4ed71ac3eb67cc90f6c49ad))
* **dashboard:** poll once at a time and initialize once ([#3470](https://github.com/headroomlabs-ai/headroom/issues/3470)) ([3201bab](https://github.com/headroomlabs-ai/headroom/commit/3201bab560088ee81b7638c66c4fc0d142cde3fb))
* render the savings each source actually reported ([56f809c](https://github.com/headroomlabs-ai/headroom/commit/56f809ce39879205a0b936ececa470956e3ab3d9))
### Dependencies
* bump baseline-browser-mapping from 2.10.16 to 2.11.21 in /docs ([#3501](https://github.com/headroomlabs-ai/headroom/issues/3501)) ([0fcdf21](https://github.com/headroomlabs-ai/headroom/commit/0fcdf21106c81cc0491d8477e1888e4c77dd2be8))
* bump next from 16.3.0 to 16.3.4 in /docs ([#3499](https://github.com/headroomlabs-ai/headroom/issues/3499)) ([2503bd7](https://github.com/headroomlabs-ai/headroom/commit/2503bd7b8d1f237f7db7401c74157619849392c1))
* bump sharp from 0.35.3 to 0.35.4 in /docs ([#3500](https://github.com/headroomlabs-ai/headroom/issues/3500)) ([d6ad35d](https://github.com/headroomlabs-ai/headroom/commit/d6ad35d472ef549a8cec922d97831244fd69447d))
* bump the cargo-minor-patch group across 1 directory with 5 updates ([#3642](https://github.com/headroomlabs-ai/headroom/issues/3642)) ([e326dd7](https://github.com/headroomlabs-ai/headroom/commit/e326dd7b591dba2e2e9f068e8a2207b1bcab65da))
* bump the npm-minor-patch group across 3 directories with 6 updates ([#3622](https://github.com/headroomlabs-ai/headroom/issues/3622)) ([2d5909c](https://github.com/headroomlabs-ai/headroom/commit/2d5909c37a40e5d8ae0c5b5e360eddb3eeb2702e))
* bump vitest from 4.1.10 to 5.0.0 in /plugins/openclaw ([#3498](https://github.com/headroomlabs-ai/headroom/issues/3498)) ([bb057d2](https://github.com/headroomlabs-ai/headroom/commit/bb057d2c62bcdcfd97e04d9f3ae32bc0dab096c6))
* bump vitest from 4.1.10 to 5.0.0 in /sdk/typescript ([#3496](https://github.com/headroomlabs-ai/headroom/issues/3496)) ([6f1251f](https://github.com/headroomlabs-ai/headroom/commit/6f1251f6f3b723d7dfe206b05993b30d043b24e5))
### Code Refactoring
* **proxy:** delete duplicate semant