上一篇我写了一条铁律:记忆只能有一本账。那篇止于”归拢”——把四家智能体的记忆搬进一处,一处为准,其余退场。
问题是退场的那几家并没有死。它们仍然在干活,仍然会发现值得记住的事实。一支笔、三个目击者,怎么协调?这周我把这个问题从头做了一遍,踩了几个坑,坑的形状比结论本身更值钱。
问题的形状
我现在日常用三个编程智能体:Claude Code 是主力,干重活、写记忆;Codex 跑独立小任务;Kimi Code 是月初刚买的国产新秀。三家各有各的指令文件格式、各有各的技能加载路径。但它们服务的是同一个人、同一套项目——我需要它们共享对我的了解,而不是各自为政。
上一轮整合解决了”记忆只记一本”。这一轮要解决的是:一套核心指令怎么保持同步、技能包怎么不走样、新发现怎么回流到唯一那本账上。
核心架构:一个真相源,四个生成物
最后落地的方案,压到一张纸上说得清:
一个 canonical 目录,放在 Dropbox 里跨设备同步,里面是核心指令(工具无关)加三份工具专属附注。一个 PowerShell 脚本,跑一次,就把这些原材料拼装成四份入口文件(Claude 的 CLAUDE.md、Codex 的 AGENTS.md、Kimi 的两份),各带一行生成头:”这是生成文件,不要手改。”
为什么是生成而非引用?Claude Code 支持 @import 导入外部文件,但那个语法只在 POSIX 路径下有案例,Windows 盘符能不能走通无法确认,且另两家根本没有 import 机制。三家对称走生成、零边角情况,胜过一家用 import 两家用复制。代价是改完核心得手动跑一次脚本——但这个代价恰好是个安全闸:你不跑,它不变。
唯一写入者 + 投递箱
记忆的写入纪律没变:只有 Claude Code 一支笔。但 Codex 和 Kimi 在干活时也会发现新事实——比如某个 API 的行为跟文档不一样,或者某个项目的截止日改了。
给它们开的通道是一个投递箱:memory_inbox/ 目录,一事一文件,三行说清”什么事、为什么值得留、来自哪里”。Claude Code 定期归并,采纳的按正式规范写进记忆,否决的连同原件一并删除。投递箱长期应该接近空;积压超过十条,说明归并没跑。
这个机制看起来笨——为什么不让三家都能写、然后用版本管理合并?因为合并冲突恰恰是上一轮”两本账”灾难的根源。三支笔同时写同一个文件,哪怕有 git,也要有人解冲突;而”有人解冲突”这件事本身就需要一个固定的裁判——绕了一圈回到单写。
不如从一开始就只允许一支笔落纸。其余工具的贡献,走”提案→审批”而非”先写→后合”。人类组织管理里最朴素的那条:写入权限越少、一致性越高。
技能同步:装机那天就种下的坑
三家共享同一套技能包(十七个),各自有安装目录。canonical 是真相源,安装区是运行副本。我写了脚本从 canonical 往安装区同步。
坑是回头看才认出来的。七月十一号我给新电脑装环境,当时把 Claude Code 的技能安装区整个复制到 Codex 的安装区——快是快,但复制前我做了一件蠢事:全局把字符串 “Claude Code” 替换成 “Codex”。本意是改掉说明文字里的工具名。实际效果:记忆路径 .claude\memory\ 被替成不存在的 .Codex\memory\,一个技能里的句子 “For Claude Code…For Claude Code” 变成了 “For Codex…For Codex” 的自相矛盾,网站发布技能里”移植到 Claude Code / Claude in Chrome”变成了”移植到 Codex / Codex in Chrome”。
这些损坏静默地躺了一周,没报错——因为技能文件只有被调用时才读,而我不是每天都调用每一个技能。直到这周做双向合并,逐文件 diff 才暴露出来。
教训很明确:跨工具复制配置时,批量字符串替换是时间炸弹。配置文件里的工具名有两种:纯说明(可改)和路径/协议名(不可改),一刀切分不清。正确做法是让共享内容从一开始就工具中立——不写死任何一家的名字,运行时由各自的 overlay 补上工具专属部分。这次合并我就把四处写死的引用改成了中性表述。
反向漂移安全闸
同步脚本解决 canonical → 安装区的方向。但如果安装区被某个工具自行改了呢?比如 Kimi 未来某天有了”自动优化指令”功能,悄悄改了安装区的文件。
我给脚本加了一道闸:同步前先比对。如果安装区的内容跟上次同步的不一样,且 canonical 也没改——说明安装区被别的力量动过——脚本不覆盖,打印逐文件的 diff 命令,中止,等人眼判。只有确认那些变动没价值(大多数时候是工具自作聪明留的格式垃圾),用 -Force 参数才会强制用 canonical 覆盖。
另一条:安装区有而 canonical 没有的文件或技能,脚本只报告、永不删。这条是血泪换的——我最初想用 Windows 的 robocopy /MIR(镜像同步,自动删除目标端多出来的文件),差点把两个只存在于安装区、还没升格进 canonical 的技能删掉。从此写死:同步脚本可以覆盖,但绝不主动删东西。删除是人的决定。
一条规则的两种表述
做完这一轮,我发现”单一真相源”这条规则在执行层其实有两种不同的表述:
对于状态(记忆、偏好、项目上下文),规则是”一支笔”:只有一个写入者,其余提案。因为状态会冲突——”这件事到底办完没有”不能同时有两个答案。
对于配置(指令、技能、脚本),规则是”一个源头 + 单向流”:改 canonical、跑脚本、安装区被动接收。因为配置不是竞争写入的问题,而是分发一致性的问题——你不怕两个人同时改,你怕改完忘了同步。
两者的共同点:真相只住在一处。区别只在于”别处怎么拿到它”——状态靠投递箱的提案-审批流,配置靠脚本的生成-覆盖流。
给同样折腾多个 AI 工具的人
如果你也在用不止一个编程智能体,我的建议是三条:
第一,趁还只有两三个的时候就决定谁是唯一写入者。等五六个各自为政了再归拢,迁移成本是指数级的——你得逐条对账,判断哪边是最新的真相,而”最新”和”正确”往往不是一回事。
第二,共享内容写工具中立。技能、指令、模板里不要硬编码任何一家的名字、路径、命令。运行时再由各自的 overlay 注入。这样切换主力工具时(这个圈子半年换一轮主角),你只改 overlay,核心不动。
第三,同步脚本要有”不同意就停下来”的能力。全自动同步看着省心,出事时覆盖也是全自动的。让脚本在检测到异常时中止、把决定权交还给你——这几秒钟的手动确认,挡得住的是若干小时的追溯修复。
这些都不是多高深的道理。难的是在还没出事的时候就愿意把闸装上——人的本能是先跑快再说,等翻了车再修护栏。我翻过一次了。这篇就是那道护栏的图纸。