ENZH

两个仓库,一个灵魂

📊 幻灯片

Clawd Soul · 第 4 篇 / 共 5 篇


上一篇讲了让 AI 学会"没用"有多难。这篇讲支撑一切的架构——两个仓库、两个 npm 依赖、2000 行代码。


身体里零行 AI 代码

整个系统分两个仓库。一个管身体,一个管大脑。

clawd-on-desk(Electron)= 身体:

  • 像素动画——12 个动画状态:发呆、思考、打字、建造、抛球、指挥、报错、开心、通知、扫地、搬运、睡觉
  • 点击、拖拽、语音气泡、聊天窗口
  • 权限弹窗——应用内 Allow/Deny,不用切回终端
  • 迷你模式——藏屏幕边缘,鼠标悬停探头
  • 眼球追踪——20fps 跟随光标,最大偏移 3px
  • 睡眠序列——打哈欠 → 打瞌睡 → 倒下 → 睡着,60 秒无操作触发
  • 主题系统——像素螃蟹 Clawd + 三花猫 Calico 两套主题

零行 AI 逻辑。一行都没有。

clawd-soul(HTTP :23456)= 大脑:

  • 屏幕阅读——vision API,1920×1080 JPEG q85
  • 性格系统——散文角色档案,5 种人格原型
  • 记忆系统——SQLite + 向量检索,三层
  • 对话系统——JSONL 存储,自动压缩
  • 情绪与信任引擎
  • 日记——每天 23:00 自动生成
  • 记忆整理——23:30 触发"做梦"
  • 11 个源文件,约 2000 行代码

分法不是代码组织偏好。是产品决策。


灵魂可以搬家

为什么非得分两个仓库?三个原因。

灵魂可迁移。 导出存档文件,换电脑导入,宠物还认得你。所有记忆、性格偏好、信任等级——全在灵魂那边。身体只是壳。

多平台没障碍。 灵魂引擎是标准 HTTP 服务,跑在任何有 Node.js 的机器上。今天是 Electron 桌面端,明天可以是 iOS app、Android widget、网页版——连的都是同一个灵魂。身体是消耗品,灵魂才持久。

各自独立迭代。 身体加新动画、新主题、新交互,不碰 AI 逻辑。灵魂改进记忆、优化 prompt、增加人格维度,不碰 UI。两边发布节奏完全独立。

身体会过时。Electron 可能淘汰,桌面端可能不再流行。身体和大脑绑死一个仓库,就是赌未来只有一种形态。


两个依赖,不是偷懒

灵魂引擎 package.json 只有两行依赖:

依赖用途
better-sqlite3SQLite 绑定
sqlite-vecSQLite 向量扩展

其余全靠 Node.js 内置模块:

功能模块
HTTP 服务器node:http
AI 服务商调用node:https(原始 HTTPS,不用 SDK)
文件读写node:fs
路径处理node:path
加密node:crypto

4 家 AI 服务商——Azure OpenAI、OpenAI、Google Gemini、Anthropic Claude——全部用原始 HTTPS 调用。没有 openai 包。没有 @anthropic-ai/sdk。就 HTTP 请求。

为什么?

每多一层 SDK 抽象,角色就多一个"泄漏"缝隙。SDK 自带重试逻辑、错误处理模式、响应格式化——这些会让对话"感觉像 AI 系统在说话",不是"宠物在说话"。栈越薄,角色越纯。

还有个实际好处:2 个依赖只有 2 个东西能出问题。整个灵魂引擎代码,一个下午从头读完。


双窗口——Windows 拖拽 bug 逼出来的架构

桌面宠物用两个独立顶层窗口:

  • 渲染窗口:大尺寸透明窗口,永久穿透点击(setIgnoreMouseEvents(true))。只负责显示 SVG 动画和眼球追踪。
  • 输入窗口:小矩形,覆盖宠物点击区域。可聚焦,接收所有指针事件。

正常思路一个窗口。但 Windows 有个拖拽 bug:WS_EX_NOACTIVATE + 分层窗口 + Chromium 子 HWND 组合,z-order 切换后产生死激活路径。点击打中幽灵区域,没反应。

排查好几个小时。最终方案:输入独立到可聚焦窗口,渲染放穿透窗口。两个窗口各管各。

输入窗口会抢焦点,已知代价。但另一个选项——Windows 拖拽彻底坏掉——更糟。

不是唯一平台兼容问题。Windows 前台窗口锁定,靠 ALT 键 trick 加 koffi FFI 调用 AllowSetForegroundWindow,再委托 PowerShell 辅助进程才解决。还有个语言子菜单截断 bug——花三小时定位,结论是 Electron + Windows DWM 不兼容,无法修复,文档标"DO NOT TOUCH"。Windows 兼容问题大部分是考古问题。


七个 agent,一只宠物

桌面宠物同时追踪 7 个 AI coding agent 会话:

Agent集成方式延迟
Claude CodeCommand hook → HTTP POST~0ms
Codex CLIJSONL 日志轮询~1.5s
Copilot CLICommand hook(camelCase)~0ms
Gemini CLISession JSON 轮询~1.5s + 4s 完成窗口
Cursor Agentstdin/stdout JSON hook~0ms
Kiro CLIAgent config 注入~0ms
opencodeIn-process Bun plugin~0ms

每个 agent 集成方式不一样。Claude Code 用 command hook,调用零依赖 Node 脚本。Codex 用增量 JSONL 日志轮询,带事件去重。opencode 最复杂:in-process Bun plugin,启动随机端口 HTTP 桥接,randomBytes(32) + timingSafeEqual 做认证——opencode 的 TUI 不对外暴露 HTTP。

7 个 agent 可以同时跑。宠物独立追踪每个会话。1 个会话 = 打字动画。2 个 = 抛球。3 个以上 = 建造。1 个子 agent = 抛球。2 个以上子 agent = 指挥。

状态优先级:error(8) > notification(7) > sweeping(6) > attention(5) > carrying/juggling(4) > working(3) > thinking(2) > idle(1) > sleeping(0)。高优先级抢占低优先级。

背后思路:程序员桌面同时跑三四个 AI agent 已是常态。宠物不能只认识一个——得认识所有工具,用动画状态告诉你发生了什么。


MIT,本地,可 hack

MIT 协议。数据 100% 本地——截屏在内存分析完就丢,不存储。存档文件是你的数据,随时导出。没有云端,没有账号,没有遥测。

写新主题,最少 1 个 SVG + 7 个动画文件。写新人格原型,一份散文档案。接入新 AI agent,一个 HTTP 集成。门槛不高。

20 个贡献者。像素画来自 @marciogranzotto 的 clawd-tank。三花猫主题是鹿鹿画的。


回头看这五篇

第 0 篇问:AI 都在抢着帮你干活,有没有一个只是陪你?第 1 篇讲性格——散文写,不用参数。第 2 篇讲记忆——三层存储加每晚做梦。第 3 篇讲反有用——让 AI 学会"没用"比有用难十倍。这篇讲架构——两个仓库、两个依赖、2000 行代码、7 个 agent。

加一起,描述很简单的东西:小生物住屏幕上,看你在干什么,记得你是谁,但不帮忙。

全部代码开源:


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0