Headroom

Persistent Installs

Install Headroom as a durable local runtime — background service, scheduled watchdog, or restartable Docker container — instead of starting it ad hoc.

Headroom can be installed as a durable local runtime instead of only being started ad hoc with headroom proxy or headroom wrap ....

Use headroom deploy when you want the one-line path: Headroom chooses the best local runtime it can run on the current host, configures detected tools, starts the proxy at http://127.0.0.1:8787, and stores the deployment profile for later lifecycle commands.

Use the lower-level Python-native headroom install CLI when you need to force a specific service, task, Docker, scope, or provider target. Both surfaces create profiles that wrap can reuse or recover instead of starting a second ephemeral proxy.

Runtime matrix

ModeWhat stays runningPrimary entrypoint
Turnkey DeployDocker, scheduled watchdog, or detached runtime selected for this hostheadroom deploy
Persistent ServiceNative background serviceheadroom install apply --preset persistent-service
Persistent TaskScheduled watchdog + on-demand runnerheadroom install apply --preset persistent-task
Persistent DockerRestartable Docker containerheadroom install apply --preset persistent-docker
On-Demand CLI (Python)Nothing after command exitsheadroom proxy
On-Demand CLI (Docker)Nothing after container exitsDocker-native wrapper / compose CLI
Wrapped (Python)Proxy lasts for wrapped sessionheadroom wrap ...
Wrapped (Docker)Containerized proxy + host tool sessionDocker-native wrapper

Quick examples

Turnkey local deployment

headroom deploy
headroom install status

deploy prefers the most capable restartable path it can prove is available. On NVIDIA workstations with Docker GPU support, such as an RTX 4090 host with the NVIDIA container runtime installed, it uses Docker GPU passthrough. Otherwise it prefers plain Docker, then the native scheduled watchdog for the host when available (launchd, Task Scheduler, or cron). If no supported supervisor is present, it still starts a managed detached Python runtime instead of failing on missing platform services.

Persistent service on the local machine

headroom install apply --preset persistent-service --providers auto
headroom install status

This installs a background service on the current machine, applies persistent tool wiring, and keeps the proxy healthy on port 8787.

Persistent watchdog task

headroom install apply --preset persistent-task --providers manual --target claude --target codex

This installs a scheduled recovery path instead of a traditional always-running service.

Persistent Docker

headroom install apply --preset persistent-docker --scope user --providers auto

This uses Docker's restart policy instead of an OS supervisor.

If you are using the Docker-native host wrapper instead of a Python install, you can use headroom install apply|status|start|stop|restart|remove for the persistent-docker preset directly from the installed wrapper. Service/task installs and provider/user/system mutation flows still belong to the Python-native CLI.

Command surface

headroom install apply
headroom install status
headroom install start
headroom install stop
headroom install restart
headroom install remove

apply creates or updates a named deployment profile, stores its manifest under ~/.headroom/deploy/<profile>/manifest.json, applies reversible configuration changes, and starts the selected runtime.

Presets and runtime kinds

Presets

  • persistent-service → native service supervisor
  • persistent-task → scheduled watchdog / recovery supervisor
  • persistent-docker → Docker restart policy with no extra OS supervisor

Runtime kinds

  • --runtime python runs headroom proxy directly
  • --runtime docker runs Headroom inside Docker while keeping the deployment managed locally

For persistent-docker, the runtime is always Docker.

Configuration scopes

ScopeWhat changes
providerTool-specific config surfaces where Headroom can make a precise reversible edit
userUser-level shell or environment surfaces
systemMachine-wide shell or environment surfaces

Provider scope today

Provider scope is intentionally conservative. The current direct adapters are:

  • Claude Code → ~/.claude/settings.json env
  • Codex → managed block in ~/.codex/config.toml
  • OpenClaw → existing wrap openclaw / unwrap openclaw flow
  • OpenCode → managed block in ~/.config/opencode/opencode.json

For Copilot, Aider, Cursor, and broader env-driven setups, prefer --scope user or --scope system.

Provider selection

OptionMeaning
--providers autoDetect supported tools on the host and configure the best available defaults
--providers allConfigure all known targets
--providers manual --target ...Configure only the named tools

Examples:

headroom install apply --providers auto
headroom install apply --providers all --scope user
headroom install apply --providers manual --target claude --target copilot

Health and wrap behavior

Persistent deployments publish the same readyz and health endpoints as ad hoc proxy runs.

/health also exposes deployment metadata when the proxy was launched through the install subsystem:

{
  "deployment": {
    "profile": "default",
    "preset": "persistent-service",
    "runtime": "python",
    "supervisor": "service",
    "scope": "user"
  }
}

The Python-native headroom wrap ... flow checks for a matching persistent deployment on the requested port before it starts a new ephemeral proxy. If an installed deployment exists but is stopped or unhealthy, it attempts to recover it first.

The Docker-native host wrapper does not yet reuse or recover persistent profiles automatically; it still starts a fresh proxy container unless you opt into --no-proxy.

Claude Code VSCode extension caveat

Persistent Claude deployments default to ENABLE_TOOL_SEARCH=true because the standalone Claude CLI benefits from deferred tool schemas.

Anthropic's VSCode extension currently does not render those deferred-tool content blocks correctly through Headroom and can show unsupported content type in the webview. If your persistent install targets Claude Code inside VSCode, edit ~/.headroom/deploy/<profile>/manifest.json, set tool_envs.claude.ENABLE_TOOL_SEARCH to "false", then restart the deployment.

Keep ENABLE_TOOL_SEARCH=true for the standalone claude CLI unless you hit the same renderer limitation there.

Docker-native relationship

The Docker-native host wrapper and the Python install CLI solve different layers of the runtime story:

  • Docker-Native Install → containerized on-demand CLI, wrapped host-tool flows, and Docker-native persistent-docker lifecycle commands
  • headroom install ... → full persistent service, task, and Docker lifecycle management, including provider/user/system mutation

For a no-Python persistent Docker workflow, use the compose-managed proxy path from docker/docker-compose.native.yml:

export HEADROOM_HOST_HOME="$HOME"
export HEADROOM_WORKSPACE="$PWD"
docker compose -f docker/docker-compose.native.yml up -d proxy

That keeps localhost:8787 stable and restarts the proxy automatically.

HEADROOM_WORKSPACE vs HEADROOM_WORKSPACE_DIR

HEADROOM_WORKSPACE (the host-side bind-mount source used by the compose file) is not the same variable as HEADROOM_WORKSPACE_DIR (the canonical Headroom state root inside the container). Both are retained; the compose file sets the latter automatically. See Filesystem Contract for the full bucket model.

On this page