一个人,四个仓库,一套把 agent 宿主从 Node.js 里拽出来、塞进 Rust 的激进方案。

先厘清:jcode 不是一个新模型

1jehuang/jcode 这个项目,名字里虽然叫 “code”,但它本身不产生代码能力。它是 coding agent harness——一个跑在终端里的 agent 宿主:把 Claude、GPT、Gemini、Copilot、Ollama、甚至 Alibaba Coding Plan 这些后端模型接进来,在本地做多会话管理、语义记忆、文件冲突仲裁、多 agent 协作调度,然后把对话界面渲染到 TUI 里。

换句话说,jcode 不和 Claude 4.7 比谁写代码更聪明,它和 Claude Code、Codex CLI、OpenCode、Cursor Agent、GitHub Copilot CLI 这些同样位于"模型和开发者之间"的宿主层比。差别在于,Claude Code 是 Node.js 写的,OpenCode 也是 Node.js,Cursor Agent 是 Electron 栈,而 jcode 全栈用 Rust 重写了一遍。

作者 Jeremy Huang 是单人主力。他同期维护的另外三个配套仓库是:

  • mermaid-rs-renderer (mmdr):纯 Rust 的 Mermaid 渲染器,不依赖浏览器,对 mermaid-cli 的 benchmark 显示 100–1400× 加速
  • handterm:Wayland-native 的终端模拟器,单进程多窗口 host 架构
  • agentgrep:带文件结构元信息的 grep,专门给 agent 吃上下文用

这四个项目互为依赖:jcode 的 TUI 需要渲染 Mermaid,于是动手写了 mmdr;想要更细粒度的滚动控制,于是开始写 handterm;想让 agent 读代码库更省 token,于是做了 agentgrep。堆栈自洽得有点疯。

许可证是 MIT,Copyright 2025 Jeremy Huang。Cargo.toml 声明版本为 0.11.4,README 的 benchmark 样本里出现过 jcode v0.9.1888-dev。换句话说,项目还在活跃的早期。

架构的几条主脉

语义记忆:把对话当向量存,把召回当反射

jcode 最有辨识度的设计是记忆层。它不是简单地在磁盘上攒一个 JSON 摘要,而是把每一轮对话做成语义向量,存进一张图:

  • 节点三类:Memory(事实 / 偏好 / 程序性知识 / 纠正 / 禁止)、Tag(显式标签)、Cluster(嵌入相似度自动发现的聚类)
  • 边六类HasTagInClusterRelatesTo{weight}SupersedesContradictsDerivedFrom

召回叫 cascade retrieval

  1. 先把当前上下文嵌入成向量,做 cosine 相似度搜索,拿到 top-10 候选
  2. 以候选为种子做 BFS 图遍历,max_depth = 2,按边类型加权(HasTag 0.8 / InCluster 0.6 / Supersedes 0.9)
  3. 候选交给一个轻量的 sidecar(当前文档写明是 GPT-5.3 Codex Spark)做相关性验证,过滤后才注入主对话

嵌入模型是本地的 all-MiniLM-L6-v2,通过 tract-onnx 推理,放在 embeddings feature flag 后面。不开这个 flag,内存占用可以压得更低——README 里 27.8 MB 的那个基线就是嵌入关闭的状态。

还有一个容易被忽略的细节:置信度按 memory type 衰减。Correction 的半衰期是 365 天,Preference 90 天,Fact 30 天,Procedure 60 天,Inferred 7 天。衰减公式把时间、访问次数、来源信任度三项揉进一个指数式里。这种设计隐含了一个立场——代码库事实会过期、用户偏好会改变、但用户的纠正是最稳的信号

值得保留警惕的是,完整的记忆生命周期并没有全部实装。docs/MEMORY_ARCHITECTURE.md 把系统分成八个阶段,前七个阶段打了 ✅(包括 per-turn 的 sidecar consolidation:写入时做重复检测与矛盾检测),而 Phase 8——也就是 ambient mode 下的全图 consolidation、跨会话的关系发现、对代码库的事实回溯验证——仍然是 📋 计划中。

Swarm:把冲突交给 server,而不是交给 git

同一个仓库里跑多个 agent,传统方案是给每个 agent 配一个 git worktree,各干各的,最后 merge。jcode 换了一个角度:不给文件加锁,也不强制 worktree,而是由 server 做文件级的读写追踪

agent A 修改了某个文件,server 检查 agent B 之前读过这个文件没。读过,就给 B 发一条通知,B 自己决定是忽略还是去看 diff。三种通信通道:

  • DM:点对点
  • Channel:topic 级的群聊
  • Broadcast:全 swarm 或本 repo 内广播

每个 agent 还能自己 spawn 子 agent,这时主 agent 自动变成 coordinator,子 agent 是 worker。生命周期状态机写得很细——spawned / ready / running / blocked / completed / failed / stopped / crashed 八种状态,每种状态变更都会通知 coordinator。

这个设计读起来很像把分布式系统的 event sourcing 套在 agent 之上。不过要泼一盆冷水:docs/SWARM_ARCHITECTURE.md 顶部明确写着 Status: Proposed。README 里放着 swarm 的演示视频,但文档自己承认这是目标态而非现状。具体到代码仓库的 jcode-corejcode-agent-runtime crate 里实装到哪一步,需要读代码去确认——这一层博文里不做断言。

Self-Dev:让 agent 改自己的源代码

README 里有这么一段描述:Tell your jcode agent to enter self dev mode, and it will start modifying its own source code.

具体机制是 jcode 把"编辑源码—编译—测试—替换自身二进制—继续现有会话"做成了一等公民。有一组专门的 infra 围绕这件事转,连 Cargo profile 都有一个 selfdev 档位(继承 release 但 opt-level = 0)。作者在 README 里加了一句不太委婉的免责声明:

It is reccomended that you use a frontier model for this. The jcode codebase is not a simple one, and weaker models can make subtle, breaking changes.

翻译过来就是,敢让 jcode 改自己的前提是你愿意付前沿模型的 token——弱一点的模型进去就是砸锅。AGENTS.md 里也写明,~/.jcode/builds/versions/<version>/jcode 存的是不可变二进制,current 是当前激活版本,self-dev 会把新编出来的二进制放到 current 下,然后让启动器符号链接指向它。

跨 harness 的 session resume

另一个容易被 README 性能对比表盖过的功能:jcode 的 /Resume 能续上 Claude Code、Codex、OpenCode、pi 的历史会话。这个能力意味着什么?意味着 jcode 对竞品的 session 存储格式做过适配——你可以把 jcode 当一个"更快的前端",而底下的对话历史不用迁移。

这种设计哲学很讨喜:不把用户绑死在自己的存储格式上。对 harness 层来说,这是非常少见的克制。

那些惊人的性能数字——以及它们背后的限定条件

README 最抢眼的部分是几张对比表。摘录其中最极端的三栏:

指标 jcode Claude Code 倍差
Time to first frame 14.0 ms 3436.9 ms 245.5×
单 session PSS(嵌入关闭) 27.8 MB 386.6 MB 13.9×
每新增 session PSS 增量 ~9.9 MB ~212.7 MB 21.5×

数字很刺激。但刺激归刺激,要把这些数据当作一类"已被独立验证的基准"来引用,证据链还不够。几点需要读者自己在心里标注:

方法学是透明的,但数据源是单一的。 README 注明:测试在一台 Linux 机器上做,每个工具采样 10 次 PTY 启动,给出了被测版本号(jcode v0.9.1888-devClaude Code 2.1.86Codex CLI 0.120.0OpenCode 1.0.203Cursor Agent 2026.04.08-a41fba1),用 PSS(Proportional Set Size)而非 RSS 来衡量内存。这比很多"我们快 10 倍"式的 marketing 要严谨得多。问题只在于,这是作者自己的机器、自己的脚本、自己的结论

第三方复述不等于独立复核。 能搜到的传播路径是:GitHub Trending Rust 上榜 → Reddit 技术区讨论 → PyShine 之类的独立技术博客整篇复述。PyShine 的文章几乎是 README 数字的二次叙述,没有独立复测。这在开源社区很正常,但不能把"被引用过"当成"被验证过"。

PSS 在行业里是有争议的。 PSS 把共享内存按进程数均摊,对"多 session 共享 runtime"这种架构天然友好——这恰好就是 jcode 的架构。不是说用 PSS 有错,而是读者要清楚:这类数字在 jcode 架构下本来就会好看,换一个工具用完全不同的进程模型,直接比 PSS 并不公平。

14 ms 的 TTFF 是启动时间,不是首个 token 的延迟。 这是两码事。Claude Code 慢在 Node.js 冷启动、依赖加载、子进程 spawn,不等于它推理慢。对最终用户而言,启动时间重要是因为它决定"打开终端敲 jcode"到"可以打字"之间的心跳感;但真正占用等待时间的大头还是后端模型的首 token 延迟,那一段 jcode 和 Claude Code 没区别。

把这些限定条件摊开,数字的价值仍然在。只是不能读成"jcode 在任何意义上都比 Claude Code 快 245 倍"——它应该被读成:“在冷启动和多 session 内存占用这两个被 Rust 最擅长优化的维度上,jcode 拉开了一到两个数量级的差距。”

技术栈:一份教科书式的 Rust terminal app 配置

Cargo.toml 列出的核心依赖几乎可以拿来当"写一个严肃的 Rust TUI 产品"的参考清单:

  • 运行时:Tokio 完整 features,futuresasync-traittokio-stream
  • TUIratatui 0.30 + crossterm 0.28(启用 event-stream)
  • HTTPreqwest 0.12(含 json/stream/blocking)、tokio-tungstenite 0.24(rustls-tls-native-roots)
  • 序列化serdeserde_jsonserde_yamltoml
  • CLIclap 4 derive 模式
  • 文件ignore(gitignore-aware 遍历)、similar(diff)、walkdirglob
  • petgraph(记忆图的 DiGraph,实装时降级成 HashMap 版本以便 JSON 序列化)
  • 嵌入jcode-embedding crate(tract-onnx 推理 all-MiniLM-L6-v2),behind feature flag,163 crates,作者专门备注"slow to compile"
  • 分配器tikv-jemallocator 可选开启,用 unprefixed_malloc_on_supported_platforms

[profile.release] 用的是 opt-level = 1codegen-units = 256incremental = true——显然优先迭代速度而非极致运行性能。真正追求分发性能的有一个单独的 release-lto profile,开 thin LTO、codegen-units = 16。区分开发和发布两套 profile,这是大型 Rust 项目里值得抄作业的做法。

workspace 拆了 40 个本地 crate(jcode-corejcode-memory-typesjcode-session-typesjcode-provider-*jcode-tui-* 系列等)。粒度细到让增量编译的边界变得清晰,代价是 cargo check --workspace 要跑一会儿。

这套东西适合谁

jcode 不是给所有人的。它的目标受众其实比 README 的激进语气暗示的更窄:

适合

  • 本身就付了 Claude / ChatGPT Pro / Copilot / Gemini 订阅,想在一台机器上并行跑多 session 的重度用户
  • 对 Node.js 启动慢、开 10 个 Claude Code session 吃掉 2.3 GB 内存这件事感到不耐烦的人
  • 愿意折腾 Rust 工具链(cargo build --release 第一次要等一段时间,163 crates 的嵌入特性尤其慢)
  • 想在自家代码上让 agent 改 agent 本体(self-dev)的极客

不适合

  • 只想打开一个 TUI 输入需求、别的什么都不想操心的用户——这种需求 Claude Code 或 Cursor Agent 的默认体验已经够用
  • 工作环境不在 Linux / macOS / WSL2 的人——虽然 Windows 列表里写了 Supported,但 Wayland 相关的能力(以及 handterm 那一路)明显是 Linux 优先
  • 对"作者自测 benchmark"有怀疑态度、需要第三方独立基准才愿意切换工具的人——至少目前,这样的基准还没有

一些值得旁观而非立刻采用的信号

技术上真正值得学习的,其实不一定是某条具体数字,而是几条设计姿态:

把记忆从"工具调用"退回到"被动反射"。 大多数 agent 框架都把 memory 做成 get / set / search 的 tool,让 LLM 自己决定什么时候用。jcode 反过来,把记忆做成语义命中后自动注入——LLM 不用知道记忆系统存在,省下的是提示词里每一轮都要描述"你有这些 memory 工具"的那段重复成本。

把多 agent 协作从 git 拉回到 server。 git worktree 方案要求 agent 理解分支模型,而实际上大多数冲突场景并不需要真正分支——只需要知道"我在改的东西别人读过了吗"。jcode 用 file-touch 通知取代锁和合并,代价是必须有一个常驻 server,收益是可以做到"把主 agent 变 coordinator、子 agent 变 worker"这种动态拓扑。

把基础设施依赖全部 in-house。 mermaid 渲染不想依赖浏览器,就自己写一个。终端滚动达不到想要的精度,就自己写一个终端。grep 返回的结果缺结构信息,就自己写一个 grep。这种做法在大厂项目里几乎不可能通过预算审批,但在单人 Rust 项目里反而是合理的——每多一个外部依赖都是长期维护债。

对作者自己也保持警惕。 README 里 self-dev 一节写着"弱模型会破坏自身",这种对工具局限性的坦诚,在工具的宣传口径里反而少见。记忆架构文档里明确标注哪些 Phase 已完成、哪些还是 📋,也是一种不取巧的表达。

一个不算结论的结论

jcode 目前还处在 0.11 版本,版本号一看就知道是个"快速迭代、不承诺稳定接口"的阶段。它的技术决策激进、文档自述诚实、性能声明透明但缺乏独立复核。如果把它当作一个"可能成为下一代 TUI agent 宿主"的候选人来看待,理由是充分的——它至少证明了用 Rust 重写这一层有多大的想象空间;如果把它当作"今天就要 all-in 的生产工具",那现在还早,等 1.0,等 swarm 从 Proposed 转成 Implemented,等有第三方独立 benchmark 出现。

至于那个 14 ms——它大概率是真的,但它也只是一个启动时间。Agent 宿主的长期价值不在启动速度,而在于它能不能帮使用者在多会话、多 agent、多 provider 的复杂工作流里少付几个数量级的"认知摩擦"。这件事,jcode 给出了一个非常独特的答卷。

参考资料