Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9d4598a
feat: add detached mode capabilities
JerrettDavis Jun 5, 2026
ca1cace
test: avoid premature cursor wrap e2e timeout
JerrettDavis Jun 5, 2026
958c21c
Merge remote-tracking branch 'upstream/main' into feat/detached-mode-…
JerrettDavis Jun 12, 2026
c34aeb5
ci: upload main test-shard coverage to codecov
JerrettDavis Jun 12, 2026
75c1c27
Merge remote-tracking branch 'upstream/main' into feat/detached-mode-…
JerrettDavis Jun 13, 2026
fe7e5de
Merge remote-tracking branch 'headroomlabs/main' into HEAD
JerrettDavis Jul 12, 2026
c8474d0
Merge remote-tracking branch 'headroomlabs/main' into pr-617-detached…
JerrettDavis Jul 14, 2026
acaf003
Merge remote-tracking branch 'headroomlabs/main' into review/pr-617-d…
JerrettDavis Jul 15, 2026
1fef94c
chore: refresh MCP server descriptor
JerrettDavis Jul 15, 2026
3c12762
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Jul 21, 2026
48f428e
fix(proxy): resolve detached-mode helper merge syntax
JerrettDavis Jul 21, 2026
1ecb4f4
fix(proxy): register detached profile setting
JerrettDavis Jul 21, 2026
2cea0c4
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Jul 28, 2026
329d5fc
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Jul 28, 2026
d3544c6
Merge remote-tracking branch 'upstream/main' into maint/pr617
JerrettDavis Aug 4, 2026
a5b5dec
chore: merge upstream main into detached capabilities
Aug 5, 2026
be211de
chore(docs): remove retired MkDocs configuration
Aug 5, 2026
74903d5
Merge remote-tracking branch 'origin/main' into maintenance/pr-617-re…
Aug 5, 2026
c770fe3
Merge remote-tracking branch 'refs/remotes/maintainer/pr617-live' int…
Aug 5, 2026
1c8e0b5
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Aug 5, 2026
9666255
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Aug 7, 2026
945edfe
fix(proxy): redact workspace path from public capabilities
Aug 7, 2026
297d3df
style(proxy): format public capability responses
Aug 7, 2026
325fc23
Merge remote-tracking branch 'refs/remotes/upstream-audit/main' into …
Aug 7, 2026
ac82e7a
fix(proxy): redact detached capability internals
Aug 9, 2026
a74fb14
Merge remote-tracking branch 'origin/main' into audit/pr617-refresh
Aug 9, 2026
78838d7
Merge remote-tracking branch 'upstream/main' into feat/detached-mode-…
Aug 10, 2026
2908fc6
Merge remote-tracking branch 'upstream/main' into maintain/617
Aug 10, 2026
8bb92fb
Merge remote-tracking branch 'origin/main' into HEAD
Aug 12, 2026
d3ee6c2
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Aug 12, 2026
452d84e
test(wrap): pin OpenCode empty-config proxy port
JerrettDavis Aug 12, 2026
0460298
Merge branch 'main' into feat/detached-mode-capabilities
JerrettDavis Aug 14, 2026
de0dbad
Merge main into feat/detached-mode-capabilities
JerrettDavis Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/content/docs/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ headroom proxy --learn --min-evidence 3
| `HEADROOM_BUDGET` | Daily budget limit in USD | -- |
| `HEADROOM_TELEMETRY` | Set to `on` for **local-only** usage stats (powers your own `/stats` and dashboard; nothing is sent externally) | `off` |
| `HEADROOM_STATELESS` | Set to `true` to disable filesystem writes | `false` |
| `HEADROOM_DETACHED_PROFILE` | Detached-mode capability policy: `strict`, `lenient`, or `silent` | `lenient` |
| `HEADROOM_MODEL_LIMITS` | Custom model config (JSON string or file path) | -- |
| `HEADROOM_BASE_URL` | Base URL of the Headroom proxy (TypeScript SDK) | `http://localhost:8787` |
| `HEADROOM_API_KEY` | Optional API key for authenticated Headroom endpoints (TypeScript SDK) | -- |
Expand Down Expand Up @@ -462,6 +463,11 @@ page for the full bucket table, plugin-author guidance, and the Docker
naming overlap note (`HEADROOM_WORKSPACE` is *not* the same as
`HEADROOM_WORKSPACE_DIR`).

For deployments where the workspace root is intentionally unavailable or
read-only, see [Detached Mode](/docs/detached-mode). It exposes the exact
capability matrix through `/capabilities`, `/health`, `/stats`, and
`headroom_feature_enabled` Prometheus gauges.

## Custom Model Configuration

Configure context limits and pricing for new or custom models:
Expand Down
57 changes: 57 additions & 0 deletions docs/content/docs/detached-mode.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
title: Detached Mode
description: Run Headroom in containers, CI, serverless, or read-only deployments with explicit capability degradation.
---

Detached mode is Headroom's contract for deployments where local writable state is absent or intentionally disabled.

Use it for stateless containers, read-only filesystems, ephemeral CI runners, serverless processes, and load-balanced fleets where local process state should not be treated as durable.

## Enable detached mode

```bash
HEADROOM_STATELESS=true headroom proxy
```

or:

```bash
headroom proxy --stateless
```

`--stateless` disables avoidable filesystem writes such as proxy file logging, local TOIN persistence, memory, learning, and telemetry beacon lock files. Request handling and compression continue to run.

## Profiles

Set `HEADROOM_DETACHED_PROFILE` or pass `--detached-profile`:

| Profile | Behavior |
|---|---|
| `lenient` | Default. Start the proxy and log the capability matrix when detached. |
| `strict` | Refuse startup when an explicitly enabled required local-state feature would degrade, such as `--memory` without available local state or a remote backend. |
| `silent` | Start the proxy without startup degradation logs. `/capabilities`, `/stats`, `/health`, and `/metrics` still expose the matrix. |

```bash
HEADROOM_STATELESS=true \
HEADROOM_DETACHED_PROFILE=strict \
headroom proxy
```

## Capability endpoint

```bash
curl http://localhost:8787/capabilities
```

The response includes `detached`, `profile`, local-state availability, every feature's local-state dependency, current state, degradation mode, and strict-mode violations.

## Metrics

The Prometheus endpoint exposes one gauge per feature:

```text
headroom_feature_enabled{feature="compression",state="full",degradation="full",dependency="none"} 1
headroom_feature_enabled{feature="session_aggregation",state="disabled",degradation="disabled",dependency="required"} 0
```

Use this to alert on degraded or disabled capabilities in managed deployments.
1 change: 1 addition & 0 deletions docs/content/docs/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"failure-learning",
"---Proxy Server---",
"proxy",
"detached-mode",
"local-llm-prefill",
"---Integrations---",
"vercel-ai-sdk",
Expand Down
5 changes: 5 additions & 0 deletions docs/content/docs/metrics.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,13 @@ headroom_latency_seconds_bucket{le="0.1"} 1150

# HELP headroom_cache_hits_total Cache hit counter
headroom_cache_hits_total 456

# HELP headroom_feature_enabled Feature availability after detached-mode capability resolution
headroom_feature_enabled{feature="compression",state="full",degradation="full",dependency="none"} 1
```

`headroom_feature_enabled` mirrors the `/capabilities` payload. Use it to alert when an expected feature is degraded or disabled in detached/stateless deployments.

### OpenTelemetry (OTLP) Export

The proxy can also push its counters to any OTLP/HTTP endpoint. Install the extra and set four variables:
Expand Down
15 changes: 15 additions & 0 deletions docs/content/docs/proxy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ headroom proxy \

Telemetry is **local-only and off by default**. `HEADROOM_TELEMETRY=on` (or `--telemetry`) turns on in-process usage stats that power your own `/stats`, `/metrics`, and dashboard — **nothing is sent to Headroom Labs**. (The anonymous aggregate beacon that older versions shipped has been removed from the code.)

For read-only, container, CI, serverless, or load-balanced deployments, use [Detached Mode](/docs/detached-mode) to make local-state degradation explicit:

```bash
headroom proxy --stateless --detached-profile lenient
```

## CLI options

### Core
Expand Down Expand Up @@ -53,6 +59,7 @@ Telemetry is **local-only and off by default**. `HEADROOM_TELEMETRY=on` (or `--t
| `--telemetry` | `false` | Enable local, in-process usage stats (for your own `/stats` and dashboard; nothing leaves the machine) |
| `--no-telemetry` | `false` | Force local telemetry off (already the default) |
| `--stateless` | `false` | Disable filesystem writes and keep runtime state in memory |
| `--detached-profile` | `lenient` | Capability policy for detached/stateless deployments: `strict`, `lenient`, or `silent` |

Use `--http-proxy` or `HEADROOM_HTTP_PROXY` when only provider API traffic should go through a proxy:

Expand Down Expand Up @@ -340,6 +347,14 @@ Live session statistics plus durable `persistent_savings` totals. Stored at `~/.
curl http://localhost:8787/stats
```

### `GET /capabilities`

Resolved detached-mode capability matrix for operators and deployment automation.

```bash
curl http://localhost:8787/capabilities
```

### `GET /stats-history`

Durable history with hourly, daily, weekly, and monthly rollups. Powers the `/dashboard` view.
Expand Down
5 changes: 4 additions & 1 deletion e2e/wrap/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,10 @@ def verify_cursor_wrap(base_env: dict[str, str], project_dir: Path) -> None:
errors="replace",
)
try:
output = wait_for_output(proc, "Press Ctrl+C to stop the proxy.", timeout=30)
# _start_proxy waits up to 45s before surfacing proxy log context. Keep
# this parent-process wait longer so slow container startup is not
# mistaken for a Cursor wrap failure.
output = wait_for_output(proc, "Press Ctrl+C to stop the proxy.", timeout=75)
# Cursor setup lines embed the /p/<name> per-project prefix.
cursor_prefix = f"/p/{quote(project_dir.name, safe='')}"
assert_true(
Expand Down
17 changes: 17 additions & 0 deletions headroom/cli/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,17 @@ def dashboard(port: int, no_open: bool) -> None:
"For containerized / read-only / load-balanced deployments. "
"(env: HEADROOM_STATELESS=true)",
)
@click.option(
"--detached-profile",
type=click.Choice(["strict", "lenient", "silent"], case_sensitive=False),
default=None,
envvar="HEADROOM_DETACHED_PROFILE",
help=(
"Detached-mode capability policy. strict refuses degraded explicitly "
"enabled local-state features; lenient logs degradations; silent only "
"exposes them through API/metrics. Env: HEADROOM_DETACHED_PROFILE."
),
)
@click.option(
"--embedding-server/--no-embedding-server",
default=False,
Expand Down Expand Up @@ -1096,6 +1107,7 @@ def proxy(
telemetry: bool,
no_telemetry: bool,
stateless: bool,
detached_profile: str | None,
embedding_server: bool,
embedding_server_socket: str | None,
) -> None:
Expand Down Expand Up @@ -1449,6 +1461,10 @@ def proxy(
license_key=license_key,
# Stateless mode: disable all filesystem writes
stateless=is_stateless,
detached_profile=cast(
Literal["strict", "lenient", "silent"],
(detached_profile or os.environ.get("HEADROOM_DETACHED_PROFILE") or "lenient").lower(),
),
# Unit 4: bounded pre-upstream concurrency on the Anthropic HTTP
# path. ``None`` -> HeadroomProxy computes ``max(2, min(8,
# os.cpu_count() or 4))``; ``<= 0`` -> disabled (unbounded).
Expand Down Expand Up @@ -1648,6 +1664,7 @@ def proxy(
GET /livez Process liveness
GET /readyz Traffic readiness
GET /health Aggregate health
GET /capabilities Detached-mode capability matrix
GET /stats Detailed statistics
GET /stats-history Durable compression history + display session
GET /metrics Prometheus metrics
Expand Down
Loading
Loading