Rust · 开源 · VibeTrail

把 ripgrep 链接进应用:VibeTrail 的无索引全文搜索

不建数据库、不做索引,直接把 grep 引擎编进 Rust 应用。

VibeTrail 是我开源的一个 coding agent 会话浏览器:Claude Code、Codex 这些工具把会话历史散落在各自的本地目录里,格式互不相同,自带的 resume 列表又只显示最近几条。VibeTrail 把它们统一成一个可浏览、可搜索、可一键恢复的界面。Rust + Tauri,macOS 应用加一个 vibetrail CLI,Apache 2.0。

设计约束:不留状态

第一版就定了一条原则:无数据库、无索引、无后台进程、无文件监听。会话文件本来就在磁盘上,直接现读。

好处很实在:没有索引就没有「索引过期」这个 bug 类别;没有后台进程就没有资源占用的负罪感;用户删掉应用不留任何垃圾。代价是搜索必须足够快——这就轮到 ripgrep 出场。

把 ripgrep 当库用

大多数人把 ripgrep 当命令行工具,但它的作者把引擎拆成了一组独立的 crate:grep-searchergrep-regexgrep-matcher。可以直接在 Cargo.toml 里引用,把搜索引擎编进自己的二进制:

  • 不需要用户装 rg,也不用打包一个外部二进制再拼参数;
  • 结果是结构化回调而不是 stdout 文本,行号、偏移、匹配区间直接拿到;
  • ripgrep 的性能红利照单全收,全库会话搜索的体感是「即时」。

各家格式各有各的怪

Provider 抽象是这个项目真正的工作量所在,每接一家都要逆向它的存储:

  • Claude Code:JSONL,一行一条消息,子 agent 会话要按父子关系折叠到根会话下;
  • Codex:同样是 JSONL,但新版本带 zstd 压缩(.jsonl.zst),还有 fork 链要归并;
  • Cursor:会话在 IDE 的 state.vscdb(SQLite)里,严格只读打开,两代存储格式都要兼容。

统一之后,UI 和 CLI 面对的是同一个接口,新接一家工具不用动上层。

恢复:最后一公里

搜到三周前那次会话只是一半,另一半是回去继续:VibeTrail 会在 Terminal、iTerm2、Ghostty 或 Warp 里打开一个新窗口,cd 到当时的项目目录,执行对应 agent 的 resume 命令。闭环是「浏览 → 搜索 → 恢复」,少一环这工具就只是个查看器。

代码在 GitHub,欢迎试用和提 issue。