我用仓颉写了个 Markdown 笔记应用,现在日常真的在用它

先把关系说清楚,免得读着像软文:cjnote 是我在 cj-tauri 仓库里写的示例应用,框架也是我写的。 所以这篇不是评测别人家的东西,是我把「为什么我认为它值得你花半小时」讲一遍——优点讲透, 短板也照实留着,你自己判断。

一句话说清它是什么

一个用仓颉写的桌面 Markdown 笔记应用。三栏布局:左边笔记库,中间编辑与实时预览, 右边 AI 助手;原生 GTK 菜单栏;AI 能真流式对话、能读你盘上的笔记、还能改你选中的段落。

架构上走的是 Tauri 那条路,也是我认定的那条:后端静态编译,前端就是系统自带的 WebView (Linux WebKitGTK / Windows WebView2)。不捆 Chromium、不带 Node、没有 npm install。

cjnote 主界面:左笔记库、中分屏编辑与预览、右 AI 助手

*开发态产物 7.6M;打包成单文件 11.2M——运行时、stdx、插件、页面、前端库、能力清单全在 一个文件里,换台机器只要系统有 WebKitGTK / GTK 就能直接跑。*

我认为它值得一看的七个理由

① 它是「活样板」,不是那种演示用的壳

演示程序只证明 API 能调通;样板得证明这套东西能撑住一个真应用。

cjnote 里笔记是真的 .md 文件、笔记库是真的目录、AI 是真接后端。日常拿来记东西完全够用—— 我这几个月写稿子的素材就是这么攒的。你要评估这套框架能不能做正经产品,看这一个应用就够, 不需要从 hello world 一步步去推演「它大概能做到哪」。

② 原生能力用得足,而且难得地「诚实」

很多跨平台方案一碰原生就露怯:菜单是页面画的、标题栏是假的、能力缺失就直接白屏。cjnote 反过来:

  • 文件 / 视图 / 帮助三个顶层原生菜单,Ctrl+N/S/O/P/Q 全套快捷键,与页面内操作同权——

不是「菜单里摆着好看」;

  • 顶栏那个「标题 · 已保存/未保存 · 字数」不是页面画的,是走 setTitlebarSubtitle 推进系统菜单行右侧的,

所以页面自己的顶栏整条都能省掉;

  • 视图菜单的三态(编辑 / 分屏 / 预览)和界面主题都是真的勾选项,和页面状态双向同步:

在页面里按 Ctrl+2,菜单里的勾跟着跳;在菜单里点「预览」,页面跟着切。

最能说明态度的是能力位降级:不是所有平台都有原生副标题(比如 WebView2 就没有), 这时候它自动退回页面自己画一条,而不是假装成功、更不是白屏。能力没有就报没有, 这条规矩省掉的是后面所有的排查工夫。

原生「视图」菜单:三态与主题都是勾选项,和页面状态同步

③ 安全模型是真在工作,不是文档里写着好看

这条是最容易被讲成口号的,所以在 cjnote 里我特意让它「看得见」:

  • 页面对文件系统没有任何直接访问,只能调注册过的命令;
  • 命令默认不放行:应用注册了 18 条命令,能力清单里明确放行 32 条(含插件命令);

没放行的前端一调就被拒,并在 stderr 留一行 尚未授权——你启动时看到的那几条 dialog:save 提示,就是这套机制在正常工作的证据;

  • 路径判定只有一处实现(框架共享层里的一个文件),前端不做任何路径检查,把路径原样交上去。

没有第二份会写错的实现,也就没有「某个入口忘了校验」这种经典事故。

④ AI 只有一条路,而且密钥根本不落在应用里

这是 cjnote 里我最想让人抄的一条设计。

页面上零 `fetch`——不是「尽量别用」,是真的一条都没有。聊天走 ws 插件连本机后端 ws://127.0.0.1:8765/ws,流式帧逐字落进对话区(delta 逐字、工具调用压成一行、审批请求内联成卡片、 done 收尾)。配置读写走宿主命令,页面没有 `~/.cjh` 的写权限。

后端 cjh 是随包分发的:应用启动先探 127.0.0.1:8765,端口上已经有活着的就直接复用、不动别人的进程, 没有才用随包二进制自己拉起,退出时只收掉自己拉起的那只。所以用户不需要装后端、不需要配路径, 而应用自己的 store.json 里一个 API Key 都没有——密钥框只脱敏回显,留空即不修改。

两个细节我认为最能体现「想清楚了」:

  • 保存是两条腿:一条写后端配置文件(管下次拉起、以及协议字段),另一条把地址 / 模型 / 密钥

即时推给正在运行的那只后端。好处是哪怕端口上那只后端是别的程序拉起来的,你在设置页改完立刻生效, 不用等重启;只有「接入协议」这一项只认配置文件、才需要重启。

  • 「测试连通」不写配置:它利用后端聊天帧支持单次覆盖(model / baseUrl / apiKey 随这一帧生效、

不落盘、不粘连),把表单里的值随一条最小对话发出去,另开会话、不污染当前对话。 于是它测的就是「我填的这组值能不能用」,而你的配置一个字都没动过。

⑤ AI 上下文只给指针,不给正文

这一条在别处很少见,但它是省 token 和「不读旧内容」的同时解。

每一问默认只带当前笔记的绝对路径(外加笔记库根),正文由 AI 自己按需 read_file 去读。 为什么不把正文塞进去?因为页面持有的文本可能已经落后于磁盘——你刚存了盘、或者别的编辑器改过, 快照就是错的。让 AI 自己去读盘,读到的永远是最新内容,顺带还省了 token。 勾上「问笔记库」才显式要求这一轮做全库检索,否则它不会替你偷偷预取一堆东西。

绝对路径是硬前提:后端的 read_file 对相对路径是按它当时的工作区解析的, 给相对路径会静默读错目录——这种坑不写下来,下一个接入的人一定踩。

⑥ 那些「只有每天用才会疼」的细节,它都处理了

样板和真应用的分界线就在这类地方,我列几个:

  • 外部文件不乱写盘:Ctrl+O 打开笔记库外面的 .md 只进内存,首次 Ctrl+S 才落成库里的新笔记,

绝不静默改写磁盘原文件;

  • 重命名是真重命名:保留原来的修改时间、拒绝覆盖已存在的目标名、删除带页内确认,外部文件直接拒绝;
  • 大纲跳过围栏:侧栏大纲抽 1~3 级标题,代码块里的 # 不算标题,点一条跳一行,

编辑器光标和预览区同步滚动;

  • 最近打开会自愈:库外打开的文件并进左侧列表(只显示文件名、悬停看完整路径),

文件被删了那一条自动清掉,最近 8 条持久化,重启还会恢复上次那篇;

  • 侧栏能拖宽:160~480px 夹取,双击复位 220px,偏好落盘,长内容的省略号不受影响;
  • 选区动作有确认:选中正文 → 重写 / 续写 / 翻译,结果先进 diff 确认条,你接受才改文档,丢弃则原样不动。

原生「文件」菜单:新建 / 打开 / 保存 / 重命名 / 删除都走宿主菜单栏

AI 设置页:接入地址、密钥、模型、协议、温度与轮数,带测试连通

⑦ 数字和证据都能自己复现,不靠「我这边跑过了」

我最不想给的就是一句「跑过了」。所以 cjnote 的每个关键结论都留了可复现的取证方式:

  • 应用注册 18 条命令,能力清单放行 32 条(含插件命令),装配 6 个插件

(store / http / log / clipboard / dialog / ws);

  • 页面自检沙盒实测 68 PASS / 0 FAIL / 1 SKIP——那 1 条 SKIP 是「环境里没有后端」的探针,

连不上就记 SKIP,不会把环境问题算成回归;

  • 开发态产物 7.6M,单文件产物 11.2M,多出来的 3.6M 就是被静态链进来的运行时与插件包,

外加内嵌的页面资源。

想自己验一遍,就两条命令(自检结论会回投 stderr):

CJNOTE_SELFCHECK=1 ./target/release/bin/main 2>&1 | grep SELFCHECK
# SELFCHECK DONE passed=68 failed=0

我特别喜欢这套自检的一点:它不只是点按钮测 UI,里面有两条是真连后端的通路—— 流式聊天探针、以及设置页的测试连通。也就是说,AI 那条链路是被自动测过的, 不是「我手动试了下能聊天」就算完。

想跑起来,三步

依赖和框架一样:仓颉 SDK 1.2.0 + 同代 stdx;Linux 另需 gcc pkg-config libwebkit2gtk-4.1-dev libgtk-3-dev。

cd examples/cjnote
bash ../../native/build_linux.sh   # 首次编 C 桥(产物落在框架根 native/)
cjpm build

export LD_LIBRARY_PATH=$CANGJIE_HOME/runtime/lib/linux_x86_64_cjnative:$CANGJIE_STDX:../../native:$LD_LIBRARY_PATH
./target/release/bin/main

工作目录就是笔记库根,首次启动会在 notes/ 下播种一篇 欢迎.md。想要一个文件的交付形态:

bash ../../scripts/pack-linux-single.sh   # → dist-single/cjnote

顺带说清一个最容易读岔的地方:7.6M 和 11.2M 不是两个程序,是同一个应用的两种产物, 差别只在「依赖有没有被编进文件里」。另外 Linux 侧有个硬天花板——系统 WebKitGTK / GTK 没有静态库, 所以「全静态 ELF」在 Linux 上不可得,能静态下来的只是框架自己带来的那部分依赖。

它的短板,我照实说

  • Windows 侧只到「代码齐备、同名导出完整」,没有实机验证。副标题这类能力位会如实降级到页面顶栏,

但你如果主力是 Windows,请把它当「预期可用、未取证」看待;

  • AI 只认 cjh 一个后端。没有「随便填个 OpenAI 地址就直连」的旁路——这是刻意的(密钥不落进应用),

但你要接别的客户端,就得走它提供的这套通路;

  • 全库检索是很朴素的 `contains`(标题 + 正文)。你拿自然语言问一句,通常 0 命中,

所以我干脆把检索这件事交给 AI 自己去做(列目录 + grep),页面不做预取;

  • 插件生态还早,你要的能力可能得自己写一个。好消息是写插件成本很低,而且不用不链接;
  • 构建有门槛:仓颉 SDK 得装好、Linux 图形开发包得齐,第一次编 C 桥要等一会儿。

谁适合拿它花半小时

  • 你在学仓颉,想知道这门语言写真实桌面应用是什么手感——它是个能跑能用的完整样本;
  • 你想要「后端静态编译 + 前端 WebView」这种轻量方案,想先看到一个 11M 单文件的成品长什么样;
  • 你在做一个要调本地 AI 后端的应用,想抄一份「页面不碰密钥、上下文给指针、流式帧怎么落」的接线方式。

三条都成立的话,我建议你的第一步不是从零写,而是把 examples/cjnote 复制一份、改掉业务逻辑—— 原生菜单、AI 通路、能力清单、单文件打包,该配的都配好了,剩下的才是你自己的东西。

全部代码 MIT。框架在 AtomGit 上, cjnote 就在 examples/cjnote/;它的 README 里连沙盒自检那条命令都写好了。

我不觉得「用新语言重写一个笔记应用」有多了不起——笔记应用满地都是。真正值钱的是它顺带证明的东西: 这套框架能让一个应用同时做到「原生能力用得真、安全边界守得住、AI 接得干净、还只要一个 11M 的文件」。 如果你在意的是后者,那 cjnote 值得你看一眼;如果你只想找个笔记软件,那用你顺手的就好。

Logo

一站式 AI 云服务平台

更多推荐