Headroom 持久化安装实战:用 headroom install 把 8787 端口常驻代理变成可管理的本地运行时
本篇指南基于 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 install CLI。
整个子系统位于 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>、健康检查 URL http://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 子系统的完整回归测试集
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00