NewTool · 架构

一个内核,三个消费者

同一个算法要同时服务 AI、人类和浏览器。多写几遍是短期最省事的做法,也是长期最贵的做法。

一个编解码工具通常会被实现很多遍:网页版一套 JS,桌面版一套,AI 调用时再让模型自己想办法。每多一个消费者,就多一份行为可能不一致的实现。

我们的做法是反过来:算法只写一次,放在 Rust 内核里,然后编译成不同形态去适配不同消费者。

内核是纯函数,没有 IO

newtool-core 里的算法全部是纯函数——输入数据、输出数据,不读文件、不发网络请求。这个约束有两个好处:一是可以编译到 wasm 在浏览器里跑,二是攻击面极小。

crates/newtool-core
01// 纯函数:无 IO,可编译到原生与 wasm
02pub fn decode_jwt(token: &str) -> Result<JwtParts, Error> {
03 let (h, p, s) = split(token)?;
04 Ok(JwtParts {
05 header: b64url_decode(h)?,
06 payload: b64url_decode(p)?,
07 signature: s.to_string(),
08 })
09}

清单是唯一事实来源

哪些算法存在、参数是什么、在哪些形态下生效——这些信息写在 manifests/algorithms.toml 里,而不是散落在代码注释或文档里。清单驱动代码生成,也驱动可见性。

manifests/algorithms.toml
01[[algorithm]]
02id = "jwt.decode"
03name = "JWT 解码"
04status = "rust" # 强制与 registry 同步
05forms = ["app", "cli", "web-wasm", "web-server"]
06
07[[algorithm.params]]
08name = "token"
09type = "string"
10required = true

build.rs 在构建期比对清单与注册表。如果清单里声明了某个算法但代码里没有实现(或反之),构建直接失败。这类校验放在构建期而不是 code review 里,是因为它会一直生效。

三个消费者,一份实现

  • AI:通过 skills 技能包或 MCP 端点调用,list / describe / run 三步
  • 人类:Tauri 2 桌面 App,通过 kernel-client 的 tauri adapter 调用
  • 浏览器:内核编译为 wasm,断网也能用,数据不出浏览器

桌面壳的 kernel-client 有三个 adapter(tauri / http / wasm),指向的是同一个内核接口。换 adapter 就是换运行环境,算法行为不变。

代价是什么

  • Rust 的迭代速度比脚本语言慢,写新算法门槛更高
  • 清单与代码的同步需要额外的构建流程与纪律
  • wasm 目标下不能用某些平台特性,算法实现要主动规避

多端行为漂移是那种「出了问题很难查、不查又一直存在」的缺陷。用构建期约束把它消灭在发生之前,比事后对齐便宜得多。

More Notes
Get in touch

把身份、Agent 与私域的复杂度,交给一套可治理的内核

无论你是要替换现有的 IAM、搭建 Agent 中台,还是想把企微私域真正运营起来——先从一次 30 分钟的架构沟通开始。我们会先判断问题是不是我们擅长解的那类,不合适会直接说。