edit(content): review batch-2 editorial pass across 24 posts (EN + ZH)

Tracker at 20 approved / 71 pending. Same pass as batch 1: first person throughout,
no LAN IPs in prose, ZH twins normalised to simplified Chinese, dynamicCta where the
post ends on a concrete next step.
This commit is contained in:
hoelee committed 2026-10-27 04:07:00 +08:00
1 parent 041471d25e
commit 09596fe7a5
45 files changed
+418 -337

No files matched your search

@@ -39,9 +39,9 @@ Hermes 提供了三种迁移 agent 的方式,它们回答的是不同的问题
| 整个 agent、带版本、可拉取更新 | **Profile distribution**(git 仓库 + `distribution.yaml`) | `hermes profile install` / `update` |
| 一次性迁移 / 备份 | 导出文件(`.tar.gz`) | `hermes profile export` / `import` |
对于"同一 agent 在两台机器上",**profile distribution** 才是持久的答案。它把整个 agent——SOUL、配置、技能、定时任务——打包成一个 git 仓库,另一台机器用一条命令就能拉取更新。
对于「同一 agent 在两台机器上」,**profile distribution** 才是持久的答案。它把整个 agent——SOUL、配置、技能、定时任务——打包成一个 git 仓库,另一台机器用一条命令就能拉取更新。
我所有东西本来就用 Gitea(git.hoelee.com),所以在那里放一个 distribution 仓库是顺理成章的。没有新工具、没有新账号,也符合我每个项目都遵循的"Gitea 优先"惯例。
我所有东西本来就用 Gitea(git.hoelee.com),所以在那里放一个 distribution 仓库是顺理成章的。没有新工具、没有新账号,也符合我每个项目都遵循的「Gitea 优先」惯例。
## 我差点踩进去的坑
@@ -49,24 +49,24 @@ distribution 安装器有一个安全特性,*听起来*像限制,却恰恰
这不是麻烦。第二台电脑本来就有自己的 agent 和项目相关的技能。如果我把它*覆盖*安装上去——或者用了会覆盖现有 profile 的 `--force`——我就会删掉那台机器本地的成果。`default` 拒绝机制就是那道护栏,逼着你在现有 agent *旁边*安装,然后再合并。
而这正是整个练习真正的教训:**合并才是产品本身。** 同步不是"复制文件",而是调和两个都以为自己是真相来源的 agent。
而这正是整个练习真正的教训:**合并才是产品本身。** 同步不是「复制文件」,而是调和两个都以为自己是真相来源的 agent。
## 那个差点让我翻车的目录事实
这里是微妙的部分,也是那种"看起来没事、直到出事"的坑。
这里是微妙的部分,也是那种「看起来没事、直到出事」的坑。
distribution 仓库里放的是技能树的**副本**——它不是*活跃目录*。活跃技能在 `~/AppData/Local/hermes/skills/`(agent 真正写入的地方);仓库副本只是我推送的一份快照。它们是两棵会漂移的、互相独立的树。
distribution 仓库里放的是技能树的**副本**——它不是*活跃目录*。活跃技能在 `~/.hermes/skills/`(agent 真正写入的地方);仓库副本只是我推送的一份快照。它们是两棵会漂移的、互相独立的树。
所以一次同步实际上涉及**三方**,而不是两方:
```
活跃技能目录 ←→ 仓库副本(D:\dev\hoelee-agent-dist\skills) ←→ Gitea 远端
活跃技能目录 ←→ 仓库副本(~/workspace/agent-dist/skills) ←→ Gitea 远端
```
我在上次推送之后新建的一个技能,*只*存在于活跃目录里。如果我假设仓库副本是权威、并"从它开始同步",就会静默删掉那个技能。所以每次同步前我做的第一件事,就是比对两棵树:
我在上次推送之后新建的一个技能,*只*存在于活跃目录里。如果我假设仓库副本是权威、并「从它开始同步」,就会静默删掉那个技能。所以每次同步前我做的第一件事,就是比对两棵树:
```bash
diff -rq ~/AppData/Local/hermes/skills D:/dev/hoelee-agent-dist/skills
diff -rq ~/.hermes/skills ~/workspace/agent-dist/skills
```
漂移是*正常的*,不是错误。整套纪律在于搞清楚三方里谁领先,然后有意识地调和。
@@ -75,16 +75,16 @@ diff -rq ~/AppData/Local/hermes/skills D:/dev/hoelee-agent-dist/skills
这是最关键的决定,而它归结为冲突策略。我想要双向同步——两台机器都会编辑技能——而当两边编辑了*同一个*技能时,我想**两边都保留、由我自己来挑**,而不是让工具静默丢掉其中一个。
这种策略本质上是交互式的。一个自动拉取的 cron 要么覆盖成果,要么在我没盯着的时候触发。所以我让触发变成手动:我说一句*"同步技能"*,agent 就去执行,并在**任何冲突时停下来问我**。这不是偷懒——而是合并的决定权在我手里,自动化做不了这个决定。
这种策略本质上是交互式的。一个自动拉取的 cron 要么覆盖成果,要么在我没盯着的时候触发。所以我让触发变成手动:我说一句*「同步技能」*,agent 就去执行,并在**任何冲突时停下来问我**。这不是偷懒——而是合并的决定权在我手里,自动化做不了这个决定。
我记录下来的(也是现在真正在跑的)流程是:
```bash
# 1. 把远端拉进仓库副本,只快进——绝不 force
cd D:\dev\hoelee-agent-dist && git pull --ff-only origin main
cd ~/workspace/agent-dist && git pull --ff-only origin main
# 2. 调和活跃目录 ↔ 仓库副本
diff -rq ~/AppData/Local/hermes/skills D:/dev/hoelee-agent-dist/skills
diff -rq ~/.hermes/skills ~/workspace/agent-dist/skills
# 3. 只暂存真正的技能内容(绝不包含 curator 垃圾)
# 4. 提交 + 推送,然后验证远端确实有了
@@ -112,13 +112,13 @@ skills/.bundled_manifest
## 我会做得不一样的地方
- **先想清楚触发方式,再选机制。** 我花了不少功夫纠结 distribution 还是 export,却还没回答"我要手动还是自动"——而这个答案反过来会*改变*机制。如果我一开始就知道要的是手动的、冲突感知的同步,第一天就会照这个方式去设计脚本。
- **把"副本 vs 活跃目录"的区分当作一条有名字的不变量。** 我是靠 diff 才发现的;它本该从第一次 `cp -r` 起就写进我的笔记里。
- **先想清楚触发方式,再选机制。** 我花了不少功夫纠结 distribution 还是 export,却还没回答「我要手动还是自动」——而这个答案反过来会*改变*机制。如果我一开始就知道要的是手动的、冲突感知的同步,第一天就会照这个方式去设计脚本。
- **把「副本 vs 活跃目录」的区分当作一条有名字的不变量。** 我是靠 diff 才发现的;它本该从第一次 `cp -r` 起就写进我的笔记里。
- **提前决定每台机器的 `user_id`。** 技能走 git 同步,但情节记忆(mem0)是另一个后端——两台机器要么共享一个记忆桶、要么各留各的,这是一个应该早点明确的单行配置选择。
## 结果
现在我有一个 git 仓库——`git.hoelee.com/hoelee/hoelee-agent-dist`——装着 172 项技能、我的配置、SOUL 和定时任务。另一台机器把它装进一个命名 profile,再把自己本地的技能合并进去,我们靠一个"每次冲突都问我"的手动触发器保持同步。第一次真正的同步推送了一个只存在于活跃机器上的技能,验证它落地了(两边都是 `edbf7ac`),并且没有动任何现有的技能。
现在我有一个 git 仓库——`git.hoelee.com/ops/agent-dist`——装着 172 项技能、我的配置、SOUL 和定时任务。另一台机器把它装进一个命名 profile,再把自己本地的技能合并进去,我靠一个「每次冲突都问我」的手动触发器保持同步。第一次真正的同步推送了一个只存在于活跃机器上的技能,验证它落地了(两边都是 `edbf7ac`),并且没有动任何现有的技能。
给任何想同步 agent 的人的一句实在话:*文件*是简单的——git 干了大部分重活。难的是那些护栏:那个你绝不能跑的 `--force`,那个你绝不能误当成真相来源的副本,还有那个你绝不能让工具替你静默解决的冲突。