Paste 是我自己用的 macOS 剪贴板工具。平时用着挺顺心,也在快速地迭代,但是很快我发现了一个现实的效率问题:复制粘贴 Agent 的计划单或者一个类型文件,很麻烦,于是我想着:能不能让这个过程变为自动的呢?这个想法迅速让我心跳加速,于是我火速开始和 Agent 的拉锯战。
1. MCP(模型上下文协议):属实是大炮打蚊子
起点很具体,Paste 里有两块状态:剪贴板列表,和钉在屏幕上的悬浮卡片。人用键盘和鼠标完成增删改查;我希望 agent 也能做同样的事。
我先想到的是 MCP。把操作写成 tools,就像我之前一直在用的 Craft note 那样,Cursor 或 Claude Desktop 或者 Codex 连上就能调,但是很快我就放弃了,因为我发现配置是真的麻烦:每个 agent 环境都要写一份,还要管一个常驻服务,我想要的是打开一个新对话,agent 立刻知道怎么用,而不是先让我配协议。
Agent 本来就会跑命令。如果所有操作都能变成:
paste-xxx items search type
paste-xxx cards show <id>再配一份 skill 告诉它二进制在哪、先查再改、用 JSON 解析结果,就不需要 MCP。把 skill 接入全局,就再也不用操心任何操作了。
还有一个更现实的原因。Paste 的列表不是打开数据库看看这么简单。内存里只驻留最近一千条和所有固定项,搜索走 SQLite FTS 和拼音;悬浮卡片是真正的 NSPanel,有自己的 session 文件,关了 App 再开也还在。如果做一个独立 CLI 去读写 clipboard.sqlite3,列表窗口和屏幕上的卡片立刻对不上。Agent 会以为删掉了,但是实际上没有。
所以 CLI 必须跟正在运行的 Paste 说话,而不是再造一份数据层。
2. 宇宙中最好的开发工具 Xcode,一 Run 就 Stop 这一块
构建快如风,
操作就断月明中,
报错细无声。
---最玄学,Grok 4.6这是让我破防的半个小时,App 从 Xcode Run 起来,agent 一碰 CLI,调试会话就停,一碰就停,我甚至怀疑必须装到 /Applications 才能测。不是的,安装之后没有调试器,信号和崩溃依旧存在,只是看不到了。
第一次,CLI 报 Paste is not running,但 socket 文件明明在。Agent 跑在沙箱里,FileManager 的 Application Support 目录会被指到别处,CLI 去错的路径找 controller.sock。Python 用 $HOME/Library/Application Support/com.eli.Paste/controller.sock 却能连上。连上之后 App 还是死。
崩溃日志比猜测有用。有两次是 SIGPIPE:Unix socket 对端一关,默认 write 会杀掉进程;有调试器时这个信号直接把 Run 停掉。修好之后还有一次,日志写得很清楚:
EXC_BREAKPOINT
queue: com.eli.Paste.controller
_dispatch_assert_queue_fail
_swift_task_checkIsolatedSwift
closure #1 in PasteController.start()Swift 6 把 start() 里的 DispatchSource 回调当成了 MainActor,而回调实际跑在 com.eli.Paste.controller 这条后台队列上。隔离断言一触发就是 SIGTRAP,Xcode 就会显示 Stop。
知道了答案,我火速让 Agent 修复。
修复是把 accept 处理提成 nonisolated static,显式标成 @Sendable,回到主线程再动 ClipboardStore。
中间还夹了一个很蠢的编译错误:stop() 粘了两遍,这个大概是我误操作了。
3. Mac 的老牌开发调试工具 Surge 是怎么做的?
Surge 提供了一个 skill:
Install the skill from the /Applications/Surge.app/Contents/Resources/Skills/ directory using a symbolic link to ensure the skill can be updated along with the application bundle.我最开始直觉地认为 Surge 底层肯定是 CLI 的,要不然怎么接入呢,不过想想就知道不合理,Surge 开发已经十余年了,早在 agent 操作 CLI 成为一个流行行为之前就存在了,不过考虑到现在 LLM 的发展速度,Surge team 砸钱用 fable5 重写了一遍底层也说不定呢。
然而我的调查让我眼前一亮。
Surge 在本机放了一个控制口:
~/Library/Application Support/com.nssurge.surge-mac/internal-controller.socksurge-cli 是 App 包里的另一个可执行文件,路径是:
/Applications/Surge.app/Contents/Applications/surge-cliCLI 不实现代理。它把命令发送给正在跑的 Surge,收回 JSON。--raw 给机器看,默认给人看。远程那套是同一协议换 TCP。协议还有版本号,新旧对不上会报错,很严谨。
而且我发现 Surge 的 Skill 压根不实现功能。它只教 agent 三件事:二进制按什么顺序找、优先用 JSON、先读状态再改、改完再读一次核对。例如先 environment / dump policy,再用最小的 set,然后复查。
这三层是分开的:
Surge.app 持有运行时
Unix socket 命令进出的门
surge-cli 发命令、打印结果
skill 告诉 agent 怎么打这些命令GUI 应用要被 agent 操作,不必把自己变成 CLI 应用。只要运行时愿意听命令,CLI 可以很轻薄。