跳转到主要内容

WRITING

开源了两个 macOS 原生应用:Ask Claude 和水利工具箱

2026年7月14日6 分钟阅读曾田力
开源macOSSwiftUIRust独立开发
开源了两个 macOS 原生应用:Ask Claude 和水利工具箱

我桌面上常年跑着一支自用的 macOS 原生小应用舰队——问 AI 的、算水利的、处理文档的、看持仓的,全是 SwiftUI 写的小工具,自己用了很久。这周把其中两个整理干净开源了:Ask Claude水利工具箱(HydroMac),顺手还带了第三个 DocTools。这篇介绍它们是什么、共用什么架构,以及开源过程里真正花功夫的那部分——把数据洗干净。

Ask Claude:给 Claude 订阅用户的原生问答窗

仓库github.com/zengtianli/ask-claude

痛点很具体:我有 Claude 订阅(Pro/Max),平时在终端里用 Claude Code CLI 问问题完全够用,但总缺一个随手的图形窗口。而市面上的 Claude 客户端几乎全走 API key——那是另一套按 token 计费的账单,订阅额度用不上。

Ask Claude 的做法是不碰 API:它直接以子进程方式调你本机已经登录的 claude 二进制(claude -p --output-format stream-json --include-partial-messages),逐行解析流式 JSON——拿到 session_id 就显示"已连接",拿到模型名就显示"opus 正在思考",text_delta 一到就增量渲染,多轮对话靠 CLI 自己的 --resume 机制。所以:

  • 零 API key、零额外账单。终端里 claude 能跑,这个 app 就能跑,用的是同一份订阅额度。
  • 不自存任何聊天记录。会话全由 Claude Code CLI 管理,和你在终端里用没有任何区别。
  • 纯 SwiftUI,一个小二进制。没有 Electron、没有 WebView、没有常驻后台进程,Release 压缩包 209KB。

要求 macOS 15+(Apple Silicon)+ 已安装并登录的 Claude Code CLI。默认用 Opus,一行 defaults write 可换模型。

水利工具箱:SwiftUI 壳 + Rust 计算核

仓库github.com/zengtianli/hydro-mac

这是我的本行。8 个水利计算器装进一个 .app:水资源年报查询、河道纳污能力(一维衰减模型)、水效评估(AHP + CRITIC 组合赋权)、水库群联合调度、平原河区多分区水量平衡、灌溉需水逐日水量平衡、分区降雨全管线、地理编码与坐标系转换。

架构上它和 Ask Claude 是同一个思路的两种形态:

一壳两层:壳永远是原生 SwiftUI,后端按形态分为直调外部 CLI 与内嵌 Rust 计算核两种
同一个壳,两种后端:Ask Claude 直接子进程调用系统里已有的 claude CLI;HydroMac 把 Rust 计算核编译成 CLI 嵌进 .app 自带。两者与后端的通信都是"起进程 + 标准输入输出传 JSON",前端里没有一行计算逻辑。

壳永远是原生 SwiftUI(swiftc 直编,连 xcodeproj 都没有);计算核是纯 Rust 的 hydro-cli,经 Foundation.Process 起进程、JSON 信封 {ok, data, error} 走标准输入输出。二进制嵌在 .app/Contents/Resources 里随包走,单 .app 自包含、完全离线可用——这对水利行业很重要,野外勘测现场经常没有网。

数值可靠性是这类工具的命:仓库自带 20 个 golden 数值回归用例(改任何计算数学必须全部通过)+ 64 个 cargo 单元测试。

开源真正的工作量:把数据洗干净

把私有仓库设成 public 只要一次点击,但那样做是事故不是开源。HydroMac 的样例数据和 golden 用例来自真实工程——真实的水库名、真实的水利分区、真实企业的取水台账,而且从第一个 commit 就在 git 历史里。所以正确路径只有一条:新开干净仓库 + 全量合成数据

这件事的工程量远超预估:

脱敏流水线:550 个实体串盘点、381 条映射、golden 全量重生成、对抗核验抓出 3 处漏网,最终残留为零
脱敏不是查找替换:先机器盘点出 550 个唯一实体串,建 381 条一致性映射(复合地名按词素自动派生),改完把 20 个 golden 用例全部重新生成并逐字段核对计算未被破坏,最后再让一个独立的对抗核验流程从零克隆公开仓来挑刺——它真抓出了 3 处漏网。

最反直觉的一处漏网值得单独说:拼音首字母码。分区的输出代码就是真实地名的拼音缩写,中文名全部洗干净了,缩写还原封不动地留在代码常量表、解析器和 golden 用例里。同类的还有 pyc 缓存里嵌着构建机的绝对路径(在另一个 app 的发布包里真抓到过)、CSV 表头里的地域缩写、xlsx 单元格内嵌的名称。教训一句话:脱敏必须查非中文形态——拼音缩写、坐标数值、二进制字符串、缓存文件,一个都不能凭感觉放过。

原生应用能有多小

三个 app 全部 adhoc 签名、无付费开发者证书,Release 压缩包的体积是原生技术栈的直接红利:

三个 app 的发布包体积对数轴对比:Ask Claude 0.21MB、DocTools 0.43MB、HydroMac 2.7MB,对照 Electron 空壳应用的 100MB+
对数轴上的差距:最大的 HydroMac 连计算核带界面 2.7MB,也只有 Electron 空壳的 1/37;最小的 Ask Claude 差着两个数量级还多。小不是炫技——下载快、启动快、内存占用小,用户拿到手的每一项体验都受益。

顺手开源的第三个是 DocTools:文档批处理工具(清理、格式互转、合并、拆分、预览),SwiftUI 壳 + Python 引擎,同样的进程 + JSON 契约,发布包 429KB。

拿去用

三个仓库都是 MIT 协议,Release 页直接挂了 arm64 压缩包。因为是 adhoc 签名,首次运行前清一次隔离标记即可:

xattr -cr "/Applications/Ask Claude.app"

或者右键 → 打开,再到「系统设置 → 隐私与安全性」放行。信不过预编译包的话,三个仓库都能一条 ./build.sh 从源码构建。

欢迎 issue 和 PR。