headroom wrap sets X-Headroom-Project but the CCR resolver reads x-headroom-project-id/x-headroom-cwd — the supported launcher doesn't satisfy its own resolver
Summary
Two different, non-overlapping header namespaces are used for two related but distinct features, and the one documented/supported launcher only sets one of them.
Per-project savings tracking (rtk gain's per-project breakdown, proxy/project_context.py:31-37
proxy/outcome.py:350+savings_tracker.py:663-665) reads:
X-Headroom-Project
which is exactly what headroom wrap sets, via cli/wrap.py:1480-1518:
_PROJECT_HEADER_NAME = "X-Headroom-Project"
def _project_name_from_cwd(): ... Path.cwd().name ...
def _apply_project_header_env(env):
env["ANTHROPIC_CUSTOM_HEADERS"] = f"{_PROJECT_HEADER_NAME}: {project}"
CCR workspace resolution (proxy/handlers/anthropic.py, see also issues #3595/#3596 filed
alongside this one) reads a different pair of headers, per
memory/storage_router.py:149-185:
x-headroom-project-id
x-headroom-cwd
So a user who runs headroom wrap claude — the officially supported entry point — still
gets CCR: workspace unresolved on every request and an empty projects map from the
per-workspace compression tracker, because wrap never sets x-headroom-project-id or
x-headroom-cwd, only X-Headroom-Project.
Also worth noting: headroom init hook ensure (cli/init.py:1058-1082) and the
tool_envs written by headroom init manifests (install/models.py) set neither header
namespace at all — they only restart the proxy process if it's down (and set
ANTHROPIC_BASE_URL/ENABLE_TOOL_SEARCH). So the gap isn't specific to non-wrap setups
either; no first-party code path currently sets x-headroom-cwd / x-headroom-project-id.
Suggested fix
Either:
- have
wrapadditionally setX-Headroom-Cwd(absolute cwd) and/orX-Headroom-Project-IdalongsideX-Headroom-Project, or - unify the two features to read the same header(s), since they both ultimately want "which project/workspace is this request for".
Env: headroom-ai 0.28.0 (pipx), macOS.
Source: headroomlabs-ai/headroom