一个聊天工具,正常剧本是账号、服务器、数据库、推送、权限、加密、客户端更新。Macaroni Messenger 偏偏把剧本撕掉了。

它的客户端只有一个 messenger.html。下载后,在 Chrome、Chromium 或 Edge 里双击打开。消息不进某个专门的聊天后端,而是变成 JSON 文件,写进 Git 仓库的 .macaroni/ 目录。

这听起来像一个坏主意。更有意思的是,它确实能跑。

一个 HTML 文件,怎么变成聊天工具

Macaroni Messenger 的架构很直:浏览器跑前端,Git 仓库存数据,GitHub API 负责写入。项目明确不建后端。

不是“暂时没做”。它的实验点就在这里:把聊天系统压到一个 HTML 文件和一个 Git 仓库里。

环节Macaroni 的做法现实含义
客户端单个 messenger.html不安装,不打包,双击运行
存储仓库 .macaroni/ 目录消息、成员、聊天元数据都是文件
消息格式JSON 文件人能看,工具也能处理
同步与历史Git/GitHub仓库历史记录天然保存变化
写入权限GitHub token需要 repository Contents 读写权限

真实使用时,用户要准备一个 GitHub 仓库,再创建 fine-grained token。权限指向 repository Contents 的读写。

目前能写入的 provider 只有 GitHub。GitLab、Gitea、Forgejo 更像未来 adapter 目标,不是现在可用的替代后端。

所以它不是给普通用户迁移聊天关系链的 IM。它更像一个可运行的极简协议样机:把“通信”这件事从平台里剥出来,看看还剩多少骨头。

它能用,但边界写得很硬

Macaroni 最诚实的地方,是没有把自己包装成安全通讯工具。项目的边界很清楚:不私密,不实时,不适合敏感对话。

问题现实限制你应该怎么判断
隐私公有仓库消息公开;私有仓库成员可读不要放敏感内容
tokentoken 存在浏览器 localStorage方便,但不是安全存储
实时性靠轮询;发不出去的先放本地 outbox不能当即时聊天系统用
扩展性大仓库会变慢高频聊天会撞墙
扩展方案近似“换一个仓库”这不是生产级扩容设计

Git 本来就不是为高频聊天消息设计的。用 Git 存消息,可以得到版本历史、文件可读、同步简单这些好处;代价也很直接:延迟、冲突、性能、权限管理都不会自动消失。

这也是它和主流 IM 的关键差别。

微信、Slack、Discord 解决的是大规模关系链、实时推送、权限治理、反垃圾、跨端体验。Macaroni 解决的是另一个问题:如果把这些都先拿掉,一条消息能不能只是一份文件。

答案是:能。但别装作没有代价。

对开发者和开源工具爱好者,它适合拿来拆架构、看协议、做小范围实验。比如团队内部演示“local-first”“文件即数据”“Git as backend”这些思路。

对关心软件复杂度和平台依赖的人,它更像一个提醒:下一次做内部小工具、低频协作工具、实验性原型时,不必一上来就拉数据库、账号系统、队列和一整套云服务。

但如果你要做公司沟通、客户支持、项目协作,或者任何涉及隐私和合规的场景,别用它扛。最现实的动作不是迁移,而是观摩。

真正刺眼的是反平台化

我更在意的不是 Macaroni 能不能流行,而是它冒犯了现代软件的一条惯性:能联网,就平台化;能注册,就账户化;能存数据,就塞进一套用户看不见的基础设施。

这条路有合理性。实时、安全、权限、审计、合规、反滥用,都是真工程。主流聊天工具不可能退回一个 HTML 文件。

问题是,复杂度经常会变味。

账户体系不只服务身份,也服务增长入口。平台同步不只服务便利,也控制关系链。客户端不只服务体验,也控制分发和留存。

“天下熙熙,皆为利来。”放到软件业,就是基础设施一旦建起来,就会反过来要求用户按它的方式生活。

Macaroni 的锋利处在这里:它没有证明“简单一定更好”,它只证明“复杂不总是必要”。

这有点像早期互联网的小工具。粗糙,任性,但边界清楚。文件就是文件,消息就是 JSON,仓库就是历史。没有增长飞轮,没有云原生话术,也没有把一个小需求包装成平台战略。

接下来该看两个变量。

一个是 adapter。它如果真能把 GitLab、Gitea、Forgejo 等写入通道补上,才算从 GitHub 玩具往更通用的协议实验迈一步。

另一个是安全边界。只要 token 仍放在 localStorage,只要消息默认跟仓库权限绑定,它就不该被误读成私密通讯工具。

这两个变量不解决,它就停在“聪明的反例”。但这个反例已经够有用。

一个 HTML 文件做聊天,荒诞;现代软件动不动就需要一整套平台才能发一句话,也荒诞。Macaroni 把两种荒诞摆在一起,让开发者重新问一次:这里真的需要一艘巨舰吗?