Headroom 持久化安装实战:用 headroom install 把 8787 端口常驻代理变成可管理的本地运行时
【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroom
本篇指南基于 Headroom 仓库的 persistent-installs 文档展开,讲清楚headroom install子系统的三大持久化预设(persistent-service / persistent-task / persistent-docker)、--scope与--providers的完整参数语义、部署清单(manifest)的存储位置与结构,以及headroom wrap如何自动复用或恢复常驻部署。读完并对照仓库源码后,你将掌握三种常驻运行时的选型依据、每个 CLI 命令的底层行为,以及 manifest 原子写入与损坏恢复等工程细节。
从临时代理到常驻运行时:persistent install 要解决什么问题
此前运行 Headroom 只有两种方式:临时起一个headroom proxy(进程退出即消失),或headroom wrap ...包一层工具会话(代理生命周期与会话绑定)。这两种方式都要求代理在需要时"恰好活着"。
Persistent Installs 让 Headroom 以持久本地运行时的形式安装到机器上:受支持的编码工具(Claude Code、Codex、Copilot 等)持续访问http://127.0.0.1:8787上一直开着的代理,而headroom wrap ...会复用或恢复这个部署,而不是再启一个第二套临时代理。文档明确建议:当你希望工具长期对接一个 always-on 代理时,使用 Python 原生的headroom installCLI。
整个子系统位于 headroom/install/ 包内,从源码结构看,各模块职责划分如下:
| 模块 | 职责 |
|---|---|
| models.py | 预设、运行时、supervisor、作用域等枚举与DeploymentManifest数据类 |
| planner.py | 目标探测、参数解析、生成规范化 manifest |
| state.py | manifest 的原子写入、加载与删除 |
| paths.py | 部署状态目录、runner 脚本路径、各工具的配置文件路径 |
| supervisors.py | systemd / launchd / 计划任务等 supervisor 的渲染与启停 |
| providers.py | 对工具配置的可逆修改(mutation)与应用/回滚 |
| runtime.py | 前台/后台运行、端口探测、健康等待、Docker 启动 |
| health.py | readyz/health端点探测 |
对应的回归测试位于 tests/test_install/,覆盖 planner、state、supervisors、runtime、health、providers、native installers 等每个模块(如 test_planner.py、test_supervisors.py)。
运行时矩阵:先选对模式,再执行命令
原文档给出的运行时矩阵是选型的核心依据,完整继承如下:
| Mode | What stays running | Primary entrypoint |
|---|---|---|
| Persistent Service | Native background service | headroom install apply --preset persistent-service |
| Persistent Task | Scheduled watchdog + on-demand runner | headroom install apply --preset persistent-task |
| Persistent Docker | Restartable Docker container | headroom install apply --preset persistent-docker |
| On-Demand CLI (Python) | Nothing after command exits | headroom proxy |
| On-Demand CLI (Docker) | Nothing after container exits | Docker-native wrapper / compose CLI |
| Wrapped (Python) | Proxy lasts for wrapped session | headroom wrap ... |
| Wrapped (Docker) | Containerized proxy + host tool session | Docker-native wrapper |
三种持久化预设的区别本质在于"谁来保证代理活着":
persistent-service交给操作系统原生服务管理器(Linux 上是 systemd unit,macOS 上是 launchd LaunchAgent);persistent-task用定时任务(cron / 计划任务)跑一个 watchdog,周期性探测并按需拉起,适合不允许注册系统服务的场景;persistent-docker则把存活责任完全交给 Docker 的 restart policy,不引入额外 OS 层监督。
快速上手:三种预设的最短命令
本机持久服务
headroom install apply --preset persistent-service --providers auto headroom install status这条命令在当前机器上安装一个后台服务,应用"持久化工具接线"(即把代理端点写进各工具配置),并保证8787端口上的代理持续健康。
从源码看,apply的完整链路是:cli/install.py 中的install命令组接收参数 → planner.py 的build_manifest()生成DeploymentManifest→ state.py 的save_manifest()落盘 → supervisors.py 的install_supervisor()注册 supervisor → runtime.py 的wait_ready()等待readyz通过。
一个值得注意的平台细节:在 Windows 上,build_manifest()会把persistent-service静默降级为persistent-task(见 planner.py 的注释)——因为 Python runner 是普通控制台进程,无法实现 Windows SCM 协议协议,sc.exe create注册的服务永远无法启动(SCM error 1053),而任务计划程序既能开机自启又能周期健康恢复,因此成为 Windows 上的有效预设(对应 issue #2552)。
持久看门狗任务
headroom install apply --preset persistent-task --providers manual --target claude --target codex这条命令安装的是"定时恢复路径"而非传统常驻服务。从 supervisors.py 看,apply会为每个 profile 渲染两个脚本:
run-headroom.sh:前台 runner,执行headroom install agent run --profile <profile>;ensure-headroom.sh:watchdog 脚本,执行headroom install agent ensure --profile <profile>,由 cron/计划任务周期性调用,发现代理挂了就拉起。
Windows 上对应的是run-headroom.ps1/run-headroom.cmd与ensure-headroom.ps1/ensure-headroom.cmd(见 paths.py)。
持久 Docker
headroom install apply --preset persistent-docker --scope user --providers auto这条命令让 Docker 的 restart policy 取代 OS supervisor。源码中有个针对该预设的实现细节:开启--memory时,Python 运行时会显式传--memory-db-path <宿主路径>,但Docker 运行时会被刻意省略该参数(见 planner.py 注释)——因为容器内 HOME 是/tmp/headroom-home,宿主的~/.headroom只是挂载进来,直接传宿主绝对路径会导致 SQLite 打不开、/readyz恒 503、部署超时回滚(issue #2803);省略后代理在容器工作目录下解析 DB,恰好落在同一个绑定挂载文件上。
另外,如果你使用的是Docker 原生宿主 wrapper(而非 Python 安装),也可以直接从已安装的 wrapper 上对persistent-docker预设执行headroom install apply|status|start|stop|restart|remove。但注意边界:service/task 安装以及 provider/user/system 的变更流程仍属于 Python 原生 CLI 的职责。
命令面:六个生命周期子命令
headroom install apply headroom install status headroom install start headroom install stop headroom install restart headroom install remove文档说明:apply会创建或更新一个具名部署档案(profile),把清单存到~/.headroom/deploy/<profile>/manifest.json,应用可逆的配置变更,然后启动所选运行时。
源码对这条命令的补充细节:
- profile 命名有校验:paths.py 中
validate_profile_name()要求 profile 只含[A-Za-z0-9._-],且不允许./..,防止路径穿越; - 目录布局:每个 profile 一个目录,除
manifest.json外还放runner.log(运行日志)、runner.pid(前台进程 pid)、各平台 runner/watchdog 脚本(见 paths.py); - 显式
--profile不容错:cli/install.py 中,如果命令行显式传了--profile但该 profile 不存在,命令会原样报错而不是悄悄转向其他已安装 profile——stop/restart/remove这类破坏性命令绝不允许误伤别的部署。只有--profile缺省时才走恢复回退(读HEADROOM_DEPLOYMENT_PROFILE环境变量或唯一的已安装 profile); remove的行为:先revert_mutations()回滚对工具配置的修改,再remove_supervisor()注销 supervisor,最后delete_manifest()删除整个 profile 目录(见 state.py 的shutil.rmtree)。
Presets 与 Runtime kinds
Presets
persistent-service-> 原生服务监督器persistent-task-> 定时看门狗 / 恢复监督器persistent-docker-> Docker restart policy,无额外 OS 监督器
这与 models.py 中的枚举一一对应:InstallPreset、SupervisorKind(service/task/none)。预设到 supervisor 的映射逻辑在build_manifest()里:service 预设产生SupervisorKind.SERVICE,task 预设产生TASK,Docker 预设产生NONE(由容器引擎负责重启)。
supervisor 的实际产物(从 supervisors.py 可见):
- Linux:
persistent-service渲染 systemd unit,scope=user时放在~/.config/systemd/user/headroom-<profile>.service,scope=system时放在/etc/systemd/system/;unit 内容为Restart=on-failure、RestartSec=5,ExecStart指向渲染出的run-headroom.sh; - macOS:渲染 launchd plist 并通过
launchctl bootstrap加载。源码还处理了一个真实的竞态:launchctl bootout之后立刻bootstrap同一 label 可能在数秒内返回 EIO,因此_bootstrap_with_retry()会重试最多 30 次(每次 0.5 秒,约 15 秒)以扛过 launchd 的释放窗口(见 supervisors.py)。
Runtime kinds
--runtime python:直接运行headroom proxy--runtime docker:在 Docker 内运行 Headroom,但部署本身仍由本机管理
对persistent-docker预设,runtime 永远是 Docker。DeploymentManifest中 Docker 相关默认值可在 models.py 看到:镜像ghcr.io/headroomlabs-ai/headroom:latest、容器名headroom-<profile>、健康检查 URLhttp://127.0.0.1:8787/readyz。
配置作用域(Scope):改到哪里、改多少
| Scope | What changes |
|---|---|
provider | Tool-specific config surfaces where Headroom can make a precise reversible edit |
user | User-level shell or environment surfaces |
system | Machine-wide shell or environment surfaces |
从 paths.py 可以看到各 scope 实际落笔的文件:
- user:
~/.bashrc、~/.zshrc、~/.profile(可写入持久环境块的文件列表); - system:Linux 上是
/etc/profile.d/headroom.sh;macOS 上是/etc/profile、/etc/zprofile、/etc/bashrc; - provider:直接编辑各工具自己的配置文件。
当前 Provider scope 支持的直接适配器
文档强调 provider scope 是有意保守的,当前的直接适配器为:
- Claude Code ->
~/.claude/settings.json的env - Codex ->
~/.codex/config.toml中的托管块(managed block) - OpenClaw -> 复用既有的
wrap openclaw/unwrap openclaw流程
对于 Copilot、Aider、Cursor 以及更宽泛的 env 驱动配置,建议用--scope user或--scope system。
与文档的一个差异值得注意:源码里PROVIDER_SCOPE_TARGETS实际包含claude、codex、openclaw、opencode四个目标(见 planner.py),且 paths.py 为 OpenCode 提供了配置路径解析(优先OPENCODE_CONFIG环境变量,其次~/.config/opencode/opencode.jsonc或opencode.json)。也就是说 OpenCode 已具备 provider 级直接适配能力,只是 Wiki 文档尚未同步更新这一条。apply对 provider scope 下不支持的 target 会明确报错列出,例如Provider scope supports only claude, codex, openclaw, and opencode(见 planner.py)。
Provider 选择:auto / all / manual
| Option | Meaning |
|---|---|
--providers auto | Detect supported tools on the host and configure the best available defaults |
--providers all | Configure all known targets |
--providers manual --target ... | Configure only the named tools |
headroom install apply --providers auto headroom install apply --providers all --scope user headroom install apply --providers manual --target claude --target copilot从 models.py 的ToolTarget枚举看,当前支持的全部 target 为:claude、copilot、codex、aider、cursor、grok_build、grok、openclaw、opencode。
auto模式的探测机制在 planner.py 的detect_targets():对每个 target 用shutil.which()查可执行文件是否在 PATH 上;若一个都没探测到,resolve_targets()会回退到默认集合claude + codex(provider scope 下再额外去掉 copilot,见 planner.py)。
生成 manifest 时,每个 target 会得到一份专属环境变量(build_install_target_envs()),代理自身的基础环境则固定写入HEADROOM_PORT、HEADROOM_HOST=127.0.0.1、HEADROOM_MODE、HEADROOM_BACKEND、显式的HEADROOM_TELEMETRY=on|off(见 planner.py)。另有两条自动派生规则:
- 若目标只含 Grok / Grok Build 且没有共享该代理的 OpenAI 系工具,自动设置
OPENAI_TARGET_API_URL指向 xAI 端点(从 providers/grok/runtime.py 引入DEFAULT_API_URL); --env显式传入的变量最后应用,可覆盖上述所有自动派生默认值。
健康端点与 wrap 的复用/恢复行为
持久化部署发布与临时代理运行完全相同的readyz和health端点。当代理经由 install 子系统启动时,/health额外暴露部署元数据:
{ "deployment": { "profile": "default", "preset": "persistent-service", "runtime": "python", "supervisor": "service", "scope": "user" } }这些字段恰好对应DeploymentManifest的同名属性(profile/preset/runtime_kind/supervisor_kind/scope),说明/health是把 manifest 中相应字段原样透出,方便运维端判断"这个 8787 端口是谁在管"。
Python 原生的headroom wrap ...流程会先检查请求端口上是否存在匹配的持久化部署,再决定是否新起临时代理;如果已安装的部署存在但处于停止或不健康状态,它会先尝试恢复它。探测逻辑基于 health.py 的probe_ready()/probe_json(),等待逻辑在 runtime.py 的wait_ready(),对/readyz轮询直到 200。
需要明确的边界:Docker 原生宿主 wrapper 尚不会自动复用或恢复持久化 profile——除非显式--no-proxy,否则它总是启动一个全新的代理容器。
Docker 原生路径的关系与 compose 管理
Docker 原生宿主 wrapper 与 Python install CLI 解决的是运行时故事的不同层:
- Docker-Native Install -> 容器化的按需 CLI、宿主工具的 wrap 流程,以及 Docker 原生的
persistent-docker生命周期命令; headroom install ...-> 完整的持久 service / task / Docker 生命周期管理,包含 provider/user/system 变更。
对于不依赖 Python的持久 Docker 工作流,使用 docker/docker-compose.native.yml 中 compose 管理的代理路径:
export HEADROOM_HOST_HOME="$HOME" export HEADROOM_WORKSPACE="$PWD" docker compose -f docker/docker-compose.native.yml up -d proxy这样可以保持localhost:8787稳定,并在容器退出时自动重启代理。
注意:
HEADROOM_WORKSPACE(compose 文件使用的宿主侧 bind-mount 源目录)与HEADROOM_WORKSPACE_DIR(容器内 Headroom 状态根的规范变量)不是同一个变量。两者都保留;compose 文件会自动设置后者。完整的 bucket 模型见 Filesystem Contract。
清单持久化的可靠性细节
manifest.json是整套安装系统的"事实来源",state.py 对它做了三层保护:
- 原子写入:
save_manifest()经由_atomic_write_text()先把 payload 写入同目录临时文件(mkstemp),flush+fsync后再os.replace()原子改名。即使写入中途被 SIGKILL、OOM 或断电打断,磁盘上也只会留下旧文件或完整新文件,绝不出现被截断的 manifest;只读文件系统则降级为告警而非崩溃。 - 损坏清单的优雅失败:
load_manifest()对解析失败(部分写入、手改、schema 漂移)抛出类型化的ManifestError,而不是裸 traceback——因为所有 install 生命周期命令以及自动执行的init hook ensure路由都要经过这里;CLI 层会把它转成可读的报错(见 cli/install.py)。 - 旧镜像仓库自动迁移:旧 manifest 若仍钉在已停止更新的
ghcr.io/chopratejas/headroom镜像上,加载时会被自动重写到组织仓库ghcr.io/headroomlabs-ai/headroom并保留 tag(issue #2426,见 state.py)。
与文档配套的其他资源
- CLI Reference:
headroom全部命令参考 - Docker-Native Install:Docker 原生安装与 wrapper 详解
- Proxy Server:代理服务端点、
readyz/health行为 - macOS LaunchAgent:macOS 上 launchd 部署的细节
- Filesystem Contract:容器内外状态目录(bucket)的完整模型
- docker/docker-compose.native.yml:无 Python 持久 Docker 的 compose 定义
- tests/test_install/:install 子系统的完整回归测试集
【免费下载链接】headroomCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.项目地址: https://gitcode.com/GitHub_Trending/head/headroom
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考