09/Documentation
管理与更新
从手机或终端更新、回滚、更新 pack、跨大版本升级、停止、卸载,以及将 0.x 安装升级至 1.0
| 你的安装方式为 | 你使用的是 | 指令写法为 |
|---|---|---|
herdr plugin install 或 herdr plugin link | Herdr 托管(herdr plugin list 显示 herdr.collie) | herdr plugin action invoke <verb> --plugin herdr.collie |
| 安装脚本或源码构建 | 独立安装 | 从安装目录运行 bin/collie <verb> |
Herdr 安装方式不会在 PATH 中添加 collie;请使用 Herdr 操作 ID(Herdr 操作)。独立安装会将二进制文件置于 ~/.local/share/collie/current/bin/collie 或 <checkout>/bin/collie 中:
# the install script's layout
cd ~/.local/share/collie/current && bin/collie version
# a source build or a linked clone
cd ~/my/collie-checkout && bin/collie version运行 bin/collie link 将二进制文件符号链接至 ~/.local/bin(将 collie 添加到 PATH)。
配置和状态位于检出目录之外,并在更新后继续保留(bridge/solo-baseline.test.ts)。.env 和 tailscale serve 记录位于配置目录中,在二进制安装中为 ~/.config/collie,在 Herdr 安装中为 Herdr 的插件配置目录;配对设备和 stt.json 位于状态目录中,即 ~/.local/state/collie,除非 COLLIE_STATE_DIR 移动了它。
通过包管理器安装的实例
如果 Collie 由包管理器安装,则更新操作也由包管理器负责,本节以下内容均不适用:
sudo pacman -Syu collie-bin # or `nix profile upgrade collie`, or `brew upgrade collie`Collie 会通过磁盘特征识别此类安装:无 .git、无 versions/ 结构、包含 release 产物附带的 manifest,且根目录处于只读状态、位于用户 home 目录之外或归 root 所有。满足最后三项中的任意一项即可触发识别。随后它会拒绝就地更新;在能够识别出具体包管理器时,还会提示对应的管理命令:
error: /opt/collie is a packaged install — updates come from your package manager.
`collie update` will not replace its files.
Take the new version with: sudo pacman -Syu collie-bin如果前缀路径未对应 Collie 已知的包管理器,它会输出前两行内容并停止,不会随意猜测你无法执行的命令。
collie doctor 将同一个安装报告为正常,且手机上的更新卡片仍然显示存在更新的版本,原本的更新按钮处变为了软件包命令。
注意。 这不是一个需要绕过的限制。该文件夹属于你的包管理器,背着包管理器替换其中的文件会导致其数据库记录的安装信息与实际不符。sudo collie update 也会以相同的方式拒绝执行。要获取新版本,请先运行你的包管理器,然后重启服务:
paru -Syu collie-bin # Arch, or your AUR helper of choice
nix profile upgrade collie # Nix
mise upgrade --bump github:AltanS/collie # mise
collie restartmise 安装属于特例:Collie 不会将其识别为打包安装,因为目录树位于你的主目录中,没有 .git 也没有 versions/ 布局,因此 collie update 会带着 cannot tell how this Collie was installed 拒绝执行且不指定管理器。mise 仍然拥有其控制权。参见 安装。
重启是 Collie 无法为你执行的部分,且不可省略。你的包管理器会在运行中的 bridge 下替换文件,因此该进程在已经报告新版本的同时仍在执行旧代码。Collie 会检测到这种不匹配并作出提示:collie doctor 会引发 restart-pending,手机端会显示“需要重启 Bridge”的横幅,内容为“Collie 在磁盘上已被替换。请重启。”一旦 collie restart 运行完毕,这两处提示都会立刻消失。
在 pack 中,打包安装的成员绝不会通过手机接收更新。pack 会将其列为“等待包管理器”,并在不包含它的情况下将此次运行计为完成,因此上述两条命令才是将其同步到最新版本的方法。
打包安装的 lead 仅拒绝其自身的迁移。手机仍会将所有成员节点同步到主控节点运行的版本,一次确认即可覆盖它们。在上述两条命令迁移主控节点后,没有任何组件会自动同步:再次点击“更新”页面,各成员节点就会跟随升级到主控节点的新版本。
更新,从手机或终端
存在两条更新路径,两者在每台主机上执行相同的步骤:在当前运行版本旁暂存新版本、切换 symlink、重启,并检查服务是否响应。在 pack lead 上,两条路径都会覆盖整个 pack。手机是简便路径。终端则是手机无法同步的机器的备用路径。
从手机更新
打开 设置 并选择 更新。卡片会显示当前运行版本、最新版本以及更新中包含的中间版本。如果主机已处于最新版本,卡片会提示该状态且不提供任何操作。


下方是预检项,每项一行:doctor、disk、bun、tree、upstream 和 service。在 lead 上,pack 中的每个成员也会接受检查。
- Green 表示正常。
- Amber 属于提示信息,绝不阻塞更新:pack 中的版本偏差、非典型安装类型、已发布但未选择跨越的大版本。代码库中未跟踪的临时文件保持为 green。
- Red 会阻塞更新。该行会指明原因,例如
collie doctor为 red、暂存构建的可用空间不足 1 GB、主机上缺少bun,或无法连接上游。若某条命令可解决该问题,卡片会将其显示为Fix: <command>。
点击 Update to <version> 会提示确认一次,确认文本含义明确:终端会话保持活跃,手机视图最多中断 30 秒。重启只会关闭 bridge,不会关闭复用器,因此 agent 保持运行,手机端重新连接后即为新版本。日常更新绝不会自动跨大版本:跨大版本升级需要单独确认,明确标出新大版本号,并提示先阅读发布说明。
运行时,卡片会显示当前状态:
| State | 含义 |
|---|---|
preflight | 正在检查本机。未做任何更改。 |
staging | 正在旧版本旁构建或下载新版本。 |
restarting | 桥接连接已主动断开。这不是故障停机。 |
verifying | 正在等待新版本响应。 |
done | 新版本已响应。 |
rolled-back | 新版本未响应,更新程序已恢复旧版本。 |
stuck | 两个版本均未响应。系统不会再次自动重启。 |
interrupted | 运行在完成前停止。没有残留的半安装状态。 |
前四项代表进度;卡片会显示该信息并提示保持屏幕开启。rolled-back 显示当前仍处于的版本、服务日志末尾内容并提供 重试。stuck 会输出需要在终端中执行的那条命令。interrupted 也会提供 重试。
在下次摘要中提醒我 会忽略卡片的提示。这不是静音:下一次推送既要等待更新的发布版本,也要等待新的时间窗口。
通知频率。 更新推送为摘要形式,每天最多一次,且绝不早于宿主机本地时间 09:00。仅包含补丁版本的变动会改为等待每周窗口,因此连续的补丁会合并为一次推送而非分四次发出;次版本或主版本更新则保持每日节奏,并顺带合并等待中的补丁。暂缓的发布版本只会合并,绝不丢弃。无论处于何种窗口,卡片始终显示当前状态。设置 → 通知(Web Push)下的 updates 通知偏好是唯一的总开关。
在 pack lead 上,按钮会显示 将 pack 更新至 <version>,一次确认即可应用于所有机器。lead 会先更新,受其自身的运行状况检查控制。随后每个 peer 逐一同步至相同版本,分别使用各自的 preflight、运行状况检查和回滚机制。没有针对单个 peer 的按钮,也没有二次确认提示。有关详细信息、两条恢复路径以及手机无法修复的一种情况,请参阅 更新 pack 中的其余节点。

每个屏幕顶部的一条横幅显示运行状态:提供的版本,然后依次是 Starting update…、Updating to <version>、Updated to <version>. Tap to reload.,最后在 peer 跟随更新时显示 Updating <n> peers: <names>。回滚的 peer 也会列在其中,并带有返回该页面的 请参阅“更新”。。横幅按以下顺序出现:




从终端执行
collie update --check # read-only preflight, --json for a script
collie update --check --local # the same, this instance only, no pack members
collie update # stage, flip, restart, verify
collie update --status # what the updater did, or is doing, --json for a script
collie update --rollback # put the previous version back
collie update --major # cross one major, see below在由 Herdr 管理的安装中,相同的动词对应 Herdr 操作:
herdr plugin action invoke update --plugin herdr.collie # Herdr-managed
bin/collie update # Standalonecollie update --check 不做任何更改。它运行 collie doctor,读取可用空间、bun 版本、工作区、上游发布列表和服务单元,并且在 lead 上会通过您自己的 SSH 向每个 pack 成员发出相同的查询。除非有项目报错,否则其退出码为 0,且 --json 会输出带有版本的报告。添加 --local 可以仅检查此实例并跳过 pack 成员。手机在其自身主机上运行该本地检查,并通过 pack 连接读取每个 peer 的状态行,因此其 preflight 不需要 SSH。
collie update 会获取当前主版本的最新发布并暂存。随后该命令将切换操作移交给独立的更新程序并退出,因为重启会终止请求更新的桥接连接。该更新程序将 current 指向新版本,通过新二进制文件重启,并轮询 GET /api/health 最多 30 秒,等待包含刚安装版本号的响应。如果未收到响应或响应来自旧版本,它会将 current 切换回原状并再次重启,同时记录包含服务日志末尾内容的 rolled-back。如果旧版本也无法启动,它会记录包含手动执行命令的 stuck,此后不再尝试重启。回滚仅执行一次,绝不执行第二次。
如果你的机器上 30 秒不够用,请设置 COLLIE_UPDATE_HEALTH_TIMEOUT_MS。超出时间预算的缓慢冷启动会被判定为更新失败并触发回滚。
collie update --status 会输出更新程序保存的记录,手机端读取的也是同一份记录。当主端口关闭时,deputy 的备用端口会在 /standby/update 上提供该记录。
如果有新的 beacon hook 事件可用,update 会输出提示以重新运行 hooks install claude。
版本存放位置
二进制安装与链接克隆在安装根目录下共享同一种布局(二进制安装为 ~/.local/share/collie 或 $COLLIE_DIR,源码检出则为克隆目录本身):
current -> versions/v1.3.0
versions/v1.3.0/
versions/v1.2.0/在源码检出中,每个 versions/vX.Y.Z 都是发布标签的 git worktree,共享同一个 .git,因此一个版本仅占用一个 worktree 的开销,而不需要第二个对象库。构建在新建的目录中运行,并在最后写入完成标记;若没有该标记,切换操作会直接拒绝,因此被中断的构建不会影响正在运行的版本。上线操作仅是对 current 符号链接的一次重命名。保留策略会保留 current 以及最新的两个历史版本,且只有成功的运行才会触发清理,因此可能需要回滚目标的运行绝不会删除该目标。
Herdr 托管 检出是特例,它会原地向前推进(ADR 0006,2026-09-03 修订)。它处于分离头指针状态且为浅克隆,存放在 Herdr 所有的目录中,因此旁边没有 versions/ 布局,无需移交,也无法切换回滚。该模式下会拒绝 --rollback;恢复路径是重新安装指定的标签(herdr plugin install AltanS/collie --ref vX.Y.Z --yes)。
验证
bin/collie update --status
herdr plugin action invoke version --plugin herdr.collie
bin/collie version预期应为最新标签。
手机端自带的 Bundle 是独立的部分。PWA 会自行检查新构建并在约一分钟内重新加载,在更新运行期间它会推迟该重新加载。如果你正在进行任务,它会显示“点击以更新”横幅并等待你点击。
如果版本未变动
collie update 每次运行都会直接查询 GitHub:源码检出查询 git ls-remote,二进制安装则查询 GitHub tags API。它不会缓存发布列表。几秒前发布的版本可能仍需要一分钟才会显示,因为 GitHub 本身需要时间同步。接下来运行 collie doctor。如果仍无法解释,请查看 当 collie 无法运行时。
跨主版本升级
update 绝不会自动跨主版本升级。
herdr plugin action invoke update-major --plugin herdr.collie # Herdr-managed
bin/collie update --major # Standalone这会将版本推进一个主版本至其最新的严格发布版。它不会以预发布版本为目标(ADR 0020)。另请参阅:从 0.x 升级至 1.0。
如果升级失败并提示 "You are not currently on a branch"
在 0.23.1 之前从 GitHub 安装的版本缺少分支跟踪引用(#63)。重新安装以恢复更新功能:
# replaces the checkout, rebuilds the UI
herdr plugin install AltanS/collie --yes
# reinstall doesn't restart the service
herdr plugin action invoke restart --plugin herdr.collie
# expect 0.23.1 or newer
herdr plugin action invoke version --plugin herdr.collie你在 Herdr 插件配置目录中的配置(按惯例为 ~/.config/herdr/plugins/config/herdr.collie)会被保留。
更新 pack 中的其余节点
通过手机更新 pack,只需一次点击和一次确认。在 lead 上打开 设置 → 更新 并选择 将 pack 更新至 <version>。按钮上方的 preflight 会覆盖所有成员,而不仅仅是 lead。如果任何位置的检查报错,按钮将被禁用,并显示失败的机器和原因。
lead 会先更新,受其自身的运行状况检查控制。只有在它稳定后,第一个 peer 才会开始。随后每个 peer 同步自身:它读取其 lead 正在运行的版本,从 GitHub 获取完全对应的 tag,并运行自己的 preflight、运行状况检查和回滚机制。peer 逐一进行。Updates 页面为每个成员保留一行:waiting、checking、staging、restarting、verifying、updated、rolled back 或 unreachable。
两项要求决定了 peer 是否能够跟进:
- peer 需要至
github.com的出站 HTTPS 访问权限。 其代码来源于此。如果没有该访问权限,peer 将被报告为落后,改由下方介绍的终端方式进行同步。 -dev+构建版本从不跟进。 运行开发构建版本的机器将保持在该版本,无论其 lead 运行什么版本。
回滚的 peer 会在 Updates 页面上显示该状态,并且不会自行重试。两条路径可供其再次尝试:

- 从手机。 一旦 lead 为最新而某个 peer 落后,按钮会显示为 重试 pack 更新。它会启动一次仅包含 peer 的新运行过程,正是该新运行过程赋予了每个 peer 再试一次的机会。
- 从终端,在 lead 上。 适用于手机完全无法同步的 peer。命令保持不变:
collie pack update <member>… # on the lead
collie pack update --all它通过您自己的 SSH 按单一步骤序列运行。它首先对每台机器进行 preflight,并将每个 peer 自己的报告与其通过 SSH 收到的响应并排打印,以便明确展示不一致之处而非将其平均化。它会请求一次同意确认。如果 lead 尚未运行它正在分发的构建版本,它随后会更新 lead 本身。接下来依次处理每个 peer:通过 git bundle 将 lead 的 commit 推送到 peer,重新构建,重启,并轮询直至其在相同的 30 秒预算内响应新构建版本。
首次失败即会停止运行过程。其后的所有成员保持不变并报告为“未尝试”,摘要中会指明清除故障所用的命令。无法完成自身更新的 lead 不会改动任何 peer。在此停止是安全的,因为 pack 允许版本偏差(PACK_PROTOCOL.md §7.1),因此半更新状态的 pack 是受支持的状态,而盲目继续则不是。
手机无法修复的一种情况。 如果在 peer 同步后手动回滚 lead,peer 的版本将领先于其 lead。没有任何机制会降级 peer:能够将 peer 回退的 lead 也能将其随意更改。该偏差是无害的,补救方法是在 lead 上运行 collie pack update <member>。
代码通过您的 SSH 传输到 peer,绝不通过 pack 连接传输(ADR 0016,附录 2026-09-04)。当 peer 自行同步时,其代码通过匿名 HTTPS 从 GitHub 获取,且由 peer 自行决定。lead 仅声明其正在运行的版本以及允许哪个 peer 继续。
如果更新器本身崩溃
当更新器消失时,上述内容都无法提供帮助。这是仅假设存在终端的处理路径。
更新器写入一条记录 <state dir>/update.json(默认为 ~/.local/state/collie/update.json,或位于 $COLLIE_STATE_DIR 下)。请先阅读它:它标明了状态、本次运行来源的版本、目标版本、更新器的 pid,并在失败时包含服务日志的尾部以及恢复命令。
由手机发起的更新完全不会输出到终端。它在自己独立的临时 systemd 单元(名为 collie-api-update-<stamp>)下运行,--collect 会在该单元退出后立即将其删除,因此其输出记录仅保存在日志(journal)中:
journalctl --user -u 'collie-api-update-*' --since '30 min ago'当手机报告成功但后续流程未发生时,就应该排查这里。例如,无法写入运行记录的警告,意味着 lead 自行完成了更新,但不会同步其 pack 的版本。网桥自己的日志记录了另一半信息:每次运行时输出一行 [pack] update <run id>: levelling peers to <version>(当 lead 获取该记录时)。如果没有这一行,则说明回合(turns)从未开始。
1.5.4 之前的版本在更新时卡在 bunx
在 1.5.4 版本之前,从手机发起的更新会在缺少你的 PATH 的临时 systemd 用户单元中运行。当检出安装(checkout install)中的 Bun 仅存在于 ~/.bun/bin 时,检出会推进,但重新构建会因 bunx: command not found 而失败。要解决此问题,请在 PATH 中包含 Bun 的终端中运行一次 collie update,或者运行 Herdr 操作(其 shim 会自行定位 Bun)。两种方法都可以重新构建已推进的检出代码。从 1.5.4 开始,更新程序会自动查找 Bun。
它旁边是 <state dir>/update.lock,保存着 pid 和时间戳。一次只允许一个运行。如果一条记录仍显示为 preflight、staging、restarting 或 verifying,且 10 分钟内未发生变化,并且其 pid 已不在进程表中,则说明该运行已结束:它被视作 interrupted,新的运行可以获取该锁。
要手动恢复上一版本,将 current 指向它并重启:
cd ~/.local/share/collie # or $COLLIE_DIR, or the checkout root
ls versions/
ln -sfn versions/<previous> current
collie restart或者让上一版本为你执行相同的操作,这就是 stuck 记录所携带的命令:
~/.local/share/collie/versions/<previous>/bin/collie update --rollback使用完整路径,而不是 collie:PATH 上的名称会通过 current 解析,而 current 正是可能出错的地方。
健康检查门禁无法捕获的情况
门禁仅证明一件事:服务已恢复并以已安装的版本响应了 /api/health。这是一个有边界的保证,而不是“绝变砖”。在门禁报告成功的同时,可能有四种情况发生损坏:
- 手机上的 web bundle 过期。 主机已处于新版本,而手机仍从其 service worker 运行旧的 JavaScript。PWA 会按自己的计划替换其 bundle;健康检查门禁无法感知它。
- 配置或 schema 迁移。 Collie 不会以此节奏发布此类迁移,更新器也不会运行任何迁移。门禁仅检查服务是否响应,而不检查其数据格式是否正确。
- 仅在交互时崩溃的 mux 驱动。 bridge 启动并响应健康检查,但 adapter 在第一次实际 attach 或 send 时失败。健康检查是一个存活性探测,而不是一致性测试运行。
- 运行旧版本代码的更新器。 分离的更新器是从正在被替换的版本中启动的。它保持小巧且稳定,并且其记录带版本控制,因此旧更新器和新 bridge 仍然可以互相理解,但这是一项缓解措施,而不是绝对保证。
在脚本中解析最新版本
查询 git 标签并按 semver 排序。避免使用 GET /repos/AltanS/collie/releases/latest,它会排除预发布版本。
# newest stable release
git ls-remote --tags --refs https://github.com/AltanS/collie | \
sed 's#.*refs/tags/##' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1预发布版本
稳定版安装不会接收预发布版本。选择加入预发布版本会跟踪该主要版本的预发布版本,直到最终版本发布(ADR 0020):
# Standalone — the install script's opt-in flag takes the newest prerelease
curl -fsSL https://colliepwa.dev/install.sh | sh -s -- --beta
# Herdr-managed — install the tag; that is the whole opt-in
herdr plugin install AltanS/collie --ref <tag> --yes
# a reinstall does not restart the service
herdr plugin action invoke restart --plugin herdr.collie使用 在脚本中解析最新版本 解析 <tag>。
要返回稳定版本:
herdr plugin install AltanS/collie --yes
herdr plugin action invoke restart --plugin herdr.collie从 0.x 升级至 1.0
如果 BUN_INSTALL 仅在 .env 中定义,请改为在 shell 配置文件或服务环境中导出它。然后运行:
# Herdr-managed
herdr plugin action invoke update-major --plugin herdr.collie
# Linked clone
bin/collie update --major使用 bin/collie version 或 herdr plugin action invoke version --plugin herdr.collie 进行验证。
对于 pack 设置: 先更新 lead,然后运行 collie pack update <member>…(更新 pack 中的其余节点)。注意:
join对于纯http://lead 需要--insecure。- 1.0 之前的邀请令牌必须使用
pack invite重新生成。 - 较旧的成员记录需要
reconnect。
1.0 对你的改变
Herdr 操作 ID 和 scripts/collie-ctl.sh 路由保持不变(ADR 0006)。
CLI 动词被编译到 <checkout>/bin/collie(命令)。使用 bin/collie link 将 collie 添加到 PATH(将 collie 添加到 PATH,ADR 0021)。
新功能:
doctor:配置诊断。
并排,如果 herd 是真实的
辅助实例配置记录在 单台主机上运行多个 Collie 实例 中。
回滚
检出最后一个 0.x 标签并重新构建:
last0x=$(git ls-remote --tags --refs origin | sed 's#.*refs/tags/##' | \
grep -E '^v0\.[0-9]+\.[0-9]+$' | sort -V | tail -1)
git fetch --depth 1 origin tag "$last0x"
git checkout --detach --force "$last0x"
rm -f bin/collie # 1.0's binary otherwise survives the rollback使用 bash scripts/collie-ctl.sh build 重新构建并调用 Herdr 的 restart 操作。状态文件(pack-trust.json、pack-runtime.json、paired-devices.json、pairing-pending.json)可以保留。回滚会移除设备配对强制要求;如果需要写保护,请配置 COLLIE_DEVICE_HEADER。
验证是否生效
检查 version 是否报告 1.0.0 或更高版本。升级后的安装不会自动配对任何设备:运行 pair 为手机签发写凭据,若手机丢失则运行 devices revoke(配对设备)。
停止或卸载
暂停服务:
herdr plugin action invoke stop --plugin herdr.collie # Herdr-managed
bin/collie stop # standalone删除服务定义和端口映射(保留 .env 和检出目录):
herdr plugin action invoke uninstall --plugin herdr.collie # Herdr-managed
bin/collie uninstall # standalone删除剩余文件:运行 herdr plugin uninstall herdr.collie(Herdr 托管),或运行 bin/collie unlink 并删除 ~/.local/share/collie / $COLLIE_DIR(独立运行)。
当 collie 无法运行时
对于二进制安装(~/.local/share/collie 或 $COLLIE_DIR),直接执行较旧的二进制文件:
ls ~/.local/share/collie/versions/
~/.local/share/collie/versions/<previous>/bin/collie update --rollback直接安装指定版本:
curl -fsSL https://colliepwa.dev/install.sh | COLLIE_TAG=v1.0.0 sh对于源码检出或 Herdr 安装,运行 git checkout <tag> 或 herdr plugin install AltanS/collie --ref vX.Y.Z --yes。
运行自定义 fork
collie update 会对比 origin 与 COLLIE_UPDATE_REPO(默认为 AltanS/collie),若两者不同则中止。如果你的 fork 自行发布标签,请设置 COLLIE_UPDATE_REPO=you/collie。
手动将上游更新合并到你的 fork:
git remote add upstream https://github.com/AltanS/collie.git
git fetch upstream --tags
git merge v1.0.0 # the tag you decided to take
# resolve the conflicts, commit the merge, then rebuild and restart:
bash scripts/collie-ctl.sh build
# Herdr-managed: invoke the `restart` action instead
bin/collie restart不要在 fork 上使用 update --major;请手动合并 v1.* 标签。运行 collie doctor 检查当前生效的 COLLIE_UPDATE_REPO。
在系统重启后保持运行
在 Linux 上,为无人值守的用户服务启用 lingering:
loginctl enable-linger $USER使用 systemctl --user status collie 验证状态。
在 macOS 上,start 会自动管理 ~/Library/LaunchAgents/herdr.collie.plist。它在用户登录时运行。使用 launchctl print gui/$(id -u)/herdr.collie 检查状态。