21.3 KB · updated 2026-07-06 · md

v0.3.0.zh.md

docs/i18n/release-notes/v0.3.0.zh.md

Tesserae v0.3.0 — 文档到代码的链接、多语言代码图、实时同步

<!-- translations:start -->

English · 한국어 · 日本語 · Русский · Español · Français · Deutsch

<!-- translations:end -->

发布于 2026-05-24 · PyPI · GitHub release · pip install --upgrade tesserae==0.3.0

Tesserae 0.3.0 闭合了文档决策与实现这些决策的代码符号之间的回路,并且把这一能力从 v0.2.0 仅支持 Python 的基础扩展到了 21 种语言。本次发布带来三项增量特性,零破坏性变更:一个 discusses 边生成阶段,会从会话发现(SessionInsightDecisionHypothesisTodoQuestionTakeaway)向匹配的代码节点铸造类型化链接;一个 tesserae project sync-code 子命令,将 colbymchenry/codegraph 的 tree-sitter SQLite 索引导入 Tesserae 的类型化 ResearchGraph;以及一个默认开启的实时 sync-code SessionStart hook,在用户编辑代码时持续保持该导入的新鲜度。三者结合,使 Tesserae 成为 2026 年版图中唯一一款能让"我们关于 X 都决定了什么?"返回出决策本身、决策所在会话、*以及*实现这些决策的具体函数 / 类 / 路由的 PKM-AI 记忆工具 —— 而且覆盖真实研究代码库实际使用的多语言技术栈。

目录:

  1. MD0 边 —— 把文档链接到代码符号(特性 H)
  2. MD0 —— CodeGraph 适配器,21 种语言
  3. 实时 sync-code SessionStart hook(v0.3.0 之后于 MD0)
  4. 从 v0.2.0 升级
  5. 战略背景

1. discusses 边 —— 把文档链接到代码符号(特性 H)

它是什么

一个可选的编译后处理阶段,会扫描每个会话发现的正文,识别其中提到的、在图中存在的代码符号,并从该发现向每个匹配的代码节点铸造一条类型化的 discusses 边。源类型是 agent harness 发出的六种会话发现类型 —— SessionInsightDecisionHypothesisTodoQuestionTakeaway —— 而目标类型涵盖 Tesserae 现在所认识的全部代码节点变体:CodeFunctionCodeClassCodeMethod,加上 v0.3.0 新增的 CodeInterfaceCodeTraitCodeStructCodeEnumCodeEnumMemberCodeTypeAliasCodeVariableCodeConstantCodeRouteCodeComponentCodeFieldCodeNamespace,以及兜底的 CodeSymbol

提取器按精确度划分为三层,以便 agent harness 能够恢复用户实际写出的标识符,同时不让大量误判涌入图中:

层级匹配的内容接受规则
强:反引号` MyClass frontend.render `始终接受 —— 作者已经把它标注成了代码。
强:点号路径frontend.rendermodels.User.save任意一段命中索引条目即接受;任意一段为停用词则拒绝。
弱:裸标识符MyClassrender(无反引号、无点号)仅当该标识符存在于代码图索引中、且通过停用词过滤后才接受(过滤掉 lenintstrTrueselfdata 等)。

多个文件中定义的符号会触发同名扇出:会话发现中对 User 的一次裸标识符提及,会为每个匹配的 CodeClass(按文件)各产生一条 discusses 边,于是下游以该发现为种子的 graph_ppr 会扩散到每一个可能的实现,而不是任意挑一个。

新增的 MCP 工具 —— find_code_symbol_mentions(node_id) —— 在查询期把同一个提取器暴露给 agent。它接收任意节点(通常是一个会话发现),返回该节点正文中提到的所有代码符号,并附带匹配的层级。这适用于你想问"这条决策实际触及了哪些符号?",而又不想重新跑一次编译阶段的场景。

如何使用

通过环境变量开启,然后编译:

export TESSERAE_INSIGHT_SYMBOL_LINK=true
tesserae project compile

启用后,每个提到已知符号的会话发现都会获得一条或多条出向 discusses 边。从 MCP 客户端:

// 找出某条决策所触及的符号
{
  "tool": "find_code_symbol_mentions",
  "arguments": { "node_id": "decision-2026-05-22-switch-to-rrf-fusion" }
}

// → 返回
// [
//   {"node_id": "code-function-tesserae.retrieval.hybrid.reciprocal_rank_fusion",
//    "tier": "backticked", "kind": "CodeFunction"},
//   {"node_id": "code-class-tesserae.retrieval.hybrid.HybridRetriever",
//    "tier": "dotted",     "kind": "CodeClass"}
// ]

或者用 graph_ppr 沿着新边游走,拉取一组决策共同触及的*代码符号邻域*:

{
  "tool": "graph_ppr",
  "arguments": {
    "seed_node_ids": [
      "decision-2026-05-22-switch-to-rrf-fusion",
      "hypothesis-2026-05-23-embedding-helps-paraphrases"
    ],
    "top_k": 20,
    "edge_type_weights": { "discusses": 3.0, "references": 1.5 }
  }
}

何时启用

  • 你的项目有真正涉及代码讨论的会话历史 —— 持续数周的项目,Claude Code 会话中确实会按名提及函数 / 类 / 路由,而不只是用散文描述行为。
  • 你希望 ask 的回答能引用具体实现的符号,而不是仅仅引用提到它的 README。
  • 你正在把这张图供给另一个工具使用(例如从决策节点做 LSP 风格的"跳转到实现"),需要一条可查询的边,而不是查询期临时再提取一次的猜测。

如果你的项目主要是散文文档和 PDF,几乎没有 Claude Code 历史,那么这个阶段会增加编译时间却产出很少有用的边 —— 保持关闭即可。

它的位置

核心实现:MD0。工具注册:tesserae/mcp_server.py

注意事项

  • 裸标识符层有意保守 —— 同时要求命中索引*且*非停用词。过于常见的标识符(rungetset)虽然能通过停用词过滤,但会被扇出到许多文件的边淹没;这是一个已知的权衡,不是 bug。
  • 同名扇出是按 kind 分别处理的:一次 User 提及若同时命中 CodeClassCodeRoute,会产生两条边。如果只想要类,请在查询期按 target.kind == "CodeClass" 过滤。
  • 该阶段在 sync-code(或 ingest-code之后运行 —— 如果你在没有代码图的情况下启用特性 H,它就没有可链接的对象,产出零条边。编译顺序由系统自动处理,无需手动编排。
  • 停用词表是全局的,并非按语言区分;一个合法地想要把 Vec 用作标识符的 Rust 项目目前已经能正常工作(Vec 不在停用词集合内),但项目级覆盖是计划中的 v0.4 后续工作。

2. tesserae project sync-code —— CodeGraph 适配器,21 种语言

它是什么

一个新的 CLI 子命令,把外部 colbymchenry/codegraph 的 SQLite 索引导入 Tesserae 的类型化 ResearchGraph。CodeGraph 是一个基于 tree-sitter 的多语言代码图提取器,自带 MCP server;适配器读取它的 .codegraph/codegraph.db,把每一行翻译成 Tesserae 的 ResearchNode,并写出 .tesserae/code-graph.json,下一次 tesserae project compile 就会接管 —— 与 v0.2.0 的 ingest-code 产物完全一致,但来源覆盖的语言基础宽广得多。

语言覆盖从 1 跃升至 21: TypeScript、JavaScript、Python、Go、Rust、Java、C#、PHP、Ruby、C、C++、Swift、Kotlin、Scala、Dart、Svelte、Vue、Liquid、Pascal/Delphi、Lua、Luau。(对于希望走纯 Python 路径、不依赖 Node 运行时的用户,v0.2.0 的 tesserae project ingest-code(基于标准库 ast 的提取器)仍然原样可用。)

为了表达 tree-sitter 在这些语言中实际暴露出的内容,v0.3.0 新增了 14 种 ResearchNodeType 变体

新节点类型表示的内容
CodeInterfaceTS/Java/C# 接口,Swift protocol
CodeTraitRust trait,Scala trait
CodeStructC/C++/Rust/Go/Swift 结构体
CodeEnumCodeEnumMember枚举及其成员(Rust、Swift、TS)
CodeTypeAliastype X = …(TS/Rust/Swift),typedef(C/C++)
CodeVariableCodeConstant顶层 let/const/var,按语言适配
CodeRouteHTTP 路由处理函数(按框架的提取器)
CodeComponentSvelte/Vue 组件、React FC 等
CodeField结构体 / 类的字段
CodeParameter函数 / 方法的参数(当 CodeGraph 输出时)
CodeNamespaceC++ namespace、C# namespace、TS namespace
CodeSymbol我们尚未类型化的任何类型的兜底

……以及 8 种新边类型implementsexportsreferencesinstantiatesoverridesdecoratestype_ofreturns。这些边直接对应于 CodeGraph 解析器在各语言上计算出的关系;Tesserae 既有的 callsimportsinherits_fromcontainsdeclared_in 边保持不变,并将继续被填充。

适配器中最关键的设计决定是 id_seed 策略。CodeGraph 自身的行 id 把 start_line 编码在内,因此每当你在符号上方多加一行空行,同一个符号就会得到一个新的 id —— 这对下游存储该 id 的边是致命的。适配器丢弃 CodeGraph 的 id,把 Tesserae 的 id 重新种为 f"{file_path}:{kind}:{qualified_name}"。结果:符号在 Tesserae 中的 id 在行号偏移的编辑下保持不变,特性 H 中会话发现的裸标识符匹配在多次编译之间都能解析到同一个节点。

如何使用

# 一次性:读取 .codegraph/codegraph.db,写出 .tesserae/code-graph.json,
# 然后下一次编译会接管。
tesserae project sync-code

# 显式指定项目根目录 + 自定义 DB / 输出路径
tesserae project sync-code \
  --project /path/to/repo \
  --db /path/to/.codegraph/codegraph.db \
  --output /path/to/.tesserae/code-graph.json

# Watch 循环 —— 每当 DB 变化时重跑 sync-code。
# 适合那些不想用特性 3 的 SessionStart hook、
# 但仍希望代码图在编辑过程中保持新鲜的人。
tesserae project sync-code --auto-sync

新项目上典型的端到端流程:

# 1. 让 CodeGraph 索引仓库(它自己的 CLI;一次性设置)
npx codegraph index .

# 2. 拉到 Tesserae 的类型化图中
tesserae project sync-code

# 3. 正常 compile 接管 code-graph.json,并(若已启用)跑特性 H
export TESSERAE_INSIGHT_SYMBOL_LINK=true
tesserae project compile

# 4. 现在可以问跨越文档和代码的问题了
tesserae project ask "Which functions implement the RRF fusion decision?"

何时启用

  • 你的项目不是纯 Python,或者不是纯 Python 加一个 Node 前端。
  • 你已经在用 CodeGraph 的 MCP server 的"find references" / "find implementations" —— 适配器让同一份索引以零额外提取成本驱动 Tesserae 的类型化图。
  • 除了函数和类之外,你还希望获得路由级或组件级粒度CodeRouteCodeComponent),这是 v0.2.0 的 ingest-code 不产出的。

如果你只用 Python,并且不想在工具链里引入 Node 运行时,那么 tesserae project ingest-code(v0.2.0)仍可使用,并产生兼容的 code-graph.json

它的位置

核心实现:MD0。CLI 接线:tesserae/cli.pysync-code 子解析器,约 897 行)。v0.2.0 的 ingest-code 子命令位于 tesserae/code_graph_extractor.py保持不变

注意事项

  • 需要一个已填充的 .codegraph/codegraph.db(即 CodeGraph 自己一次性的 npx codegraph index . 步骤)。如果 DB 缺失,适配器会以可操作的错误消息快速失败。
  • CodeGraph 的解析器在 21 种语言上属于尽力而为;在病态的泛型或宏密集代码中偶尔会出现未解析的引用。适配器记录 CodeGraph 输出的内容,不再尝试重新解析。
  • 某些节点类型(CodeParameterCodeField)只有在 CodeGraph 的对应语言提取器暴露它们时才会产出 —— 覆盖度因语言而异。兜底的 CodeSymbol 类型会接住 tree-sitter 看到的、我们尚未类型化的任何东西,所以不会有内容被静默丢弃。
  • 原子写入使用 PID + 随机后缀 作为临时文件名(而不是共享的 .tmp),以避免两次并发的 sync-code 调用发生冲突 —— 这与最近落地在 batch manifest writer 中的修复保持一致。

3. 实时 sync-code SessionStart hook(v0.3.0 之后于 main

它是什么

Tesserae 插件中的一个小型 SessionStart hook,它闭合了"代码图持续更新"的回路。CodeGraph 的 MCP server 本身已经会自动监视文件系统,让 .codegraph/codegraph.db 在你编辑时保持新鲜 —— 但 Tesserae 的 .tesserae/code-graph.json 只有在你手动跑 sync-code 时才会刷新。这个 hook 会在 Claude Code 每次打开会话时将 tesserae project sync-code --project <root> 放到后台运行,仅当 SQLite DB 比派生的 JSON 更新时才会执行。

默认开启;可在项目级通过 .claude/tesserae.local.md 的 frontmatter 退出:

---
hooks:
  sync_code_on_start: false
---

只要满足下列任一条件,hook 就会静默跳过,因此它绝不会给不使用 CodeGraph 的项目添加噪音:

  • 项目不使用 CodeGraph(没有 .codegraph/codegraph.db)。
  • .tesserae/code-graph.json 已经与 DB 同样新或更新。
  • tesserae 二进制不在 PATH 上。
  • 同一项目根目录下已经有另一个 sync-code 在运行(基于 pgrep 的重入守卫,与 0a3d35f 中落地的 SessionEnd compile 守卫一致)。
  • 用户已通过 sync_code_on_start: false 退出。

当 hook 真的触发时,你会在会话头部看到一行:

  ⟳ syncing code-graph from CodeGraph (background)

……而实际的 sync-code 调用以脱离当前会话的方式运行(setsidnohup → 兜底的裸 &),输出捕获到 .tesserae/.session-start-hook.log,方便你检查发生了什么,且不会泄漏到 Claude 的会话脚本里。

该 hook 在 v0.3.0 之后落地在 main(PR #11,提交 395e9fb),将随下一次 compile / plugin marketplace 发布;v0.3.0 PyPI 本身并不打包它,因为 hook 位于插件中,而非 tesserae Python 包中。

如何使用

如果你通过 Claude Code marketplace 安装了 Tesserae 插件,那它已经在你身上了 —— hook 默认开启。要确认它跑过:

tail -n 20 .tesserae/.session-start-hook.log

要在单个项目(例如更偏好 ingest-code 的纯 Python 仓库)中关掉它:

mkdir -p .claude
cat > .claude/tesserae.local.md <<'EOF'
---
hooks:
  sync_code_on_start: false
---

This project uses `tesserae project ingest-code` (Python AST) instead of
the CodeGraph adapter, so the live sync-code hook is disabled.
EOF

要在不等待新会话的情况下强制做一次性同步,直接跑 tesserae project sync-code 即可 —— hook 与手动命令共享同一个 pgrep 守卫,所以不会重复执行。

何时启用

  • 你想要"持续更新"的属性,而不必每次编辑后都记得手动跑 sync-code
  • 你的编辑会话短而频繁(打开会话、问一个问题、关闭)—— hook 能确保每个新会话都看到一份当前的代码图。
  • 你已经在用 CodeGraph 的 MCP server 加文件监视 —— hook 只是把这份新鲜度传播到 Tesserae。

如果你处于紧凑的内循环里、不希望每个会话都派生任何后台工作,或者项目根本不使用 CodeGraph,那就保持关闭(后者 hook 会静默 no-op,但显式 opt-out 更干净)。

它的位置

  • Hook 入口:MD0
  • 设置解析:MD0 —— read_plugin_setting 表新增了 sync_code_on_start=true 的默认值。
  • 重入守卫:与 SessionEnd compile 守卫(hooks/session-end.sh)采用同一套 pgrep -f "tesserae project sync-code.*${project_root}" 模式。

注意事项

  • Hook 只在 SessionStart 时触发,并不会在每次文件保存时跑。如果你想在编辑过程中(不开新的 Claude 会话)持续运行 sync-code,请在另一个终端用特性 2 中的 tesserae project sync-code --auto-sync
  • mtime 比较使用 BSD stat -f %m(macOS)→ GNU stat -c %Y(Linux)→ [[ A -nt B ]] 兜底。在 mtime 分辨率较低的奇异文件系统上,偶尔会跳过一次在 CodeGraph 索引完成后不到一秒就发起的同步 —— 下一次会话会补上。
  • 后台派生优先使用 setsid,其次 nohup,最后裸 &。在极度受限的 shell 中,如果以上都无法把进程脱离会话,sync 仍会运行,但可能让会话启动阻塞几秒。请在这种情况下打开一个对终端友好的 shell,或者设置 sync_code_on_start: false

从 v0.2.0 升级

pip install --upgrade tesserae==0.3.0

这就是全部升级动作 —— v0.3.0 是增量发布,零破坏性变更。默认 tesserae project compile 行为不变;新部分都是可选并可被发现的。

新可选阶段(特性 1)的环境变量:

# 启用编译后的文档到代码 discusses 边阶段(特性 H)
export TESSERAE_INSIGHT_SYMBOL_LINK=true

值得加入肌肉记忆的新 CLI 子命令(特性 2):

tesserae project sync-code             # 一次性 CodeGraph → Tesserae 导入
tesserae project sync-code --auto-sync # watch 循环

v0.2.0 的 tesserae project ingest-code 子命令仍然原样可用 —— 项目使用 Python 之外的任何东西就选 sync-code,不想要 Node 运行时依赖就选 ingest-code

agent 现在可用的新 MCP 工具(特性 1):

  • find_code_symbol_mentions(node_id) —— 在查询期对任意节点正文做符号提取。

新插件设置(特性 3,v0.3.0 之后于 main):

# .claude/tesserae.local.md
---
hooks:
  sync_code_on_start: true   # 默认值;设为 false 可关闭实时 sync hook
---

其余一切 —— graph_ppr、混合 search_nodesembedding_statuslist_communitiesfresh_insights、社区摘要、衰减打分、supersedes、schema 漂移、斜杠命令、wiki / Obsidian 投影 —— 相对于 v0.2.0 保持不变。


战略背景

Tesserae v0.2.0 奠定了类型化代码图节点和文档侧的基础原语(衰减、supersedes、社区摘要)。v0.3.0 是两半连接起来的版本:特性 H 从决策与假设向其所触及的符号铸造类型化的 discusses 边,而 CodeGraph 适配器让这些符号覆盖真实研究代码库实际使用的多语言技术栈 —— TypeScript、Rust、Go、Swift 及另外 17 种 —— 而不仅仅是 Python。

我们在本里程碑之前调研的第一波 PKM-AI 版图中,没有其他工具做到这一点。Cursor Memories 是按项目的文本袋 —— 没有图、没有类型化边。Claude CLAUDE.md 是一个扁平的 markdown 文件。Cline memory-bank 是一个 markdown 目录,没有类型化提取。Aider CONVENTIONS.md 是一个 prompt-prefix 文件。它们都没有把一条文档决策链接到实现它的函数或类;它们都不知道 DecisionCodeRoute 是不同类型的事物。v0.3.0 跨越 21 种语言的类型化代码节点的 discusses 边就是切入点 —— 而实时 SessionStart hook 让这一切入点感觉像是*环境本身的一种属性*,而不是一个需要用户记住的工作流。

更宽广的 GraphRAG 空间中最接近的同行 —— Microsoft GraphRAG —— 拥有类型化实体和社区摘要(Tesserae v0.2.0 也映射了这些),但完全没有代码图层;它是一个语料 RAG 系统,不是项目记忆编译器。HippoRAG 2 的 PPR 原语(Tesserae v0.2.0)和 Mem0 的记忆操作(Tesserae v0.2.0 的 supersedes)补齐了文档侧的先进状态。v0.3.0 加入了它们都未触及的维度:从 agent 自己的发现,类型化地连边到表示这些发现所涉代码的类型化节点,并覆盖真实代码库实际使用的语言

另见:

  • v0.2.0 release notes —— 类型化检索、代码图(Python)、本体演进
  • 架构总览 —— 模块图与流水线
  • 特性图 —— 含源链接的完整特性状态表
  • Sessions 集成 —— 特性 H 所链接的会话发现源节点
  • MCP 集成 —— 完整的 MCP 工具列表(新增的 find_code_symbol_mentions 工具将在下一轮文档中加入此处)