hist-bridge
# hist-bridge
**用多个 AI 编程 Agent 协作时,在它们之间无缝衔接同一个对话。**
当你用 Claude Code、Codex、Cursor 等多个 Agent 编码时——它们各有所长,但**上下文断在每个工具里、互不相通**。hist-bridge 把它们打通:在当前 Agent 里**列出 / 搜索 / 摘要 / 载入**其它 Agent 的历史会话,把它当作上下文**接着往下做**;再用「会话链 (thread)」把跨工具的多次往返**当成一个连续对话来统一管理**。
> 一句话:**同一个编码任务,让不同 Agent 协同接力,而不是各聊各的。** 想用 Codex 起草、用 Claude 深挖、用 Cursor 调,中间不丢上下文——这就是 hist-bridge 解决的事。
> 实现上是**上下文接力**(把历史对话作为上下文喂给当前 Agent 继续),不是无损的完整状态重放——跨厂商的内部推理状态/工具执行状态无法迁移。对"接着聊、接着做"而言完全够用。
>
> 支持来源:Claude Code、Codex、Cursor(含在 Cursor 里用 GLM 跑的会话)、以及另一个 z.ai 后端的 Claude Code(GLM)。
## 它能读哪些历史
| 来源 (source) | 存储 | 说明 |
|---|---|---|
| `claude` | `~/.claude/projects/<slug>/<uuid>.jsonl` | Claude Code 原生 transcript |
| `codex` | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` + `session_index.jsonl` | Codex CLI rollout |
| `cursor` | `<Cursor globalStorage>/state.vscdb`(SQLite) | Cursor 的 composer/bubble;**在 Cursor 里用 GLM 跑的会话也在这里**,按 model 区分(GLM-5/GLM-5.1) |
| `glm` | 另一个 Claude Code(z.ai 后端)的 `projects` 目录 | 与 claude 同格式,默认关闭,需配 root |
## 暴露的 MCP 工具
- `list_sources()` — 列出已配置来源及是否可用。
- `list_conversations({source?, project?, query?, limit?})` — 列历史会话,按时间倒序。
- `get_conversation({source, id, format?, max_messages?, include_reasoning?, include_tools?})` — 把某次会话渲染成可续接内容。`format`:`markdown`(完整 transcript,默认)| `summary`(紧凑交接卡)| `json`(结构化)。
- `summarize_conversation({source, id})` — 抽取式压缩成「🎯目标 / ✅已完成 / ⚠️卡点 / 📋待办 / 🧭最后状态」交接卡。**无需 LLM、确定性、省上下文**,长会话优先用它。
- `search_conversations({query, source?, limit?})` — 跨来源全文检索(先标题,后正文)。
**会话链 (thread) —— 把跨工具的多次会话当成一个连续对话:**
- `link_thread({title?, members:[{source,id}...]})` — 把若干会话按 hop 顺序标记为同一条逻辑对话。
- `list_threads()` — 列出所有链及成员(含每个成员是否可用)。
- `get_thread({thread_id, format?, max_messages?})` — 把整条链的成员会话**按序合并**成一个连续转写;**自动剥掉 hist-bridge 自己嵌入过的转写块**(`# 历史会话:` / `# 🗂 交接摘要:`)避免历史重复。
- `summarize_thread({thread_id})` — 对整条链出一张交接卡。
- `append_to_thread({thread_id, source, id})` — 在另一个工具续接产生新会话后,把它接到链尾。
- `unlink_thread({thread_id})` — 删除链(只删关联,不动底层会话)。
线程元数据存在用户级目录(win:`%APPDATA%\hist-bridge\threads.json`;mac/linux:`~/.config/hist-bridge/threads.json`),可用 `HIST_BRIDGE_THREAD_STORE` 覆盖。**典型用法**:在 Claude 聊→载入 Codex 续→`link_thread claude:<id> codex:<新id>`→以后任一工具 `get_thread`/`summarize_thread` 就能把整条往返当一个对话载入,不再套娃。
### 摘要器(省上下文)
长会话(几十上百条消息)直接全量载入会吃掉大量上下文。`summarize_conversation` / `format:"summary"` 用确定性规则从归一化对话里抽取:首条用户消息→目标;write/edit 工具参数→改动文件;shell 命令→已运行命令;`isError` 结果→卡点;工具自带的 todo 列表(Cursor `todos`、Claude `TodoWrite`)→待办;最后一条真实用户/助手消息→当前状态。一张卡通常只有原文的几十分之一,但保留了「目标 + 进度 + 下一步」——续接问答足够。
## 安装
```bash
npm install
npm run build # 生成 dist/
```
### 在 Claude Code 用
**方式 A — 直接注册 MCP server(最快):**
```bash
claude mcp add --scope user hist-bridge -- node "<绝对路径>/hist-bridge/dist/server.js"
```
之后在 Claude Code 里直接说:「列出我最近的 codex 对话」「把第 3 个载进来接着聊」。重启 Claude Code 生效。
**方式 B — 作为插件安装(额外带 `/resume` 命令和续接技能):**
本仓库已是合法插件结构(`.claude-plugin/plugin.json` 内联了 MCP server 声明,外加 `commands/` + `skills/`)。通过你的插件 marketplace 或本地插件机制安装后,会多出:
- `/hist-bridge:resume [codex|glm|claude|搜索词]` 斜杠命令
- `continue-foreign` 技能(自动梳理目标/已完成/未完成再续接)
### 在 Codex 用
编辑 `~/.codex/config.toml`,加:
```toml
[mcp_servers.hist-bridge]
command = "node"
args = ["<绝对路径>/hist-bridge/dist/server.js"]
startup_timeout_sec = 20
```
然后在 Codex 里就能调 `list_conversations` / `get_conversation` 等工具。Codex 自己的历史它本来就能 `codex resume`;这个 server 额外给它跨工具 + 统一检索。
## 配置 GLM 来源
GLM 有两个去处,按你怎么用分别覆盖:
1. **在 Cursor 里用 GLM** → 已被 `cursor` 来源自动覆盖,按 `model` 字段(GLM-5 / GLM-5.1 等)就能认出来,无需额外配置。
2. **在另一个 z.ai 后端的 Claude Code 里用 GLM**(文件格式同 Claude Code)→ 启用 `glm` 来源:
- 环境变量(最简单):`HIST_BRIDGE_GLM_ROOT=<那个实例的 projects 目录>`(自动启用)。
- 或改 `config.json` 里 `sources.glm.root` 并把 `enabled` 设为 `true`。
- 若那份历史在另一台机器,把对应的 `.jsonl` 同步过来再指向即可。
## Cursor 来源说明
- 默认按平台自动探测 `state.vscdb` 路径(win/mac/linux);也可在 `config.json` 的 `sources.cursor.root` 指定。
- 读取时会先把 `state.vscdb` 拷到临时目录再以只读打开,**不碰你正在运行的 Cursor**,也不会写回。
- 同一个库里也存着 `cursorAuth/*` 令牌——本工具只读 `composerData`/`bubbleId`,不会导出这些密钥。
## 调试 CLI(不连 MCP 直接试)
```bash
npm run cli -- sources
npm run cli -- list [codex|cursor|glm|claude] [--project X] [--query Y] [--limit N]
npm run cli -- get <source> <id> [--max N] [--json] [--reasoning]
npm run cli -- summarize <source> <id> # 紧凑交接卡
npm run cli -- search <关键词> [source]
```
## 已知边界
- 会话格式是各工具私有且会变的;解析器做了防御,但厂商改格式时可能需要更新适配器。
- Codex 的推理(reasoning)是加密的,无法还原;Claude 不在 transcript 里存 system prompt(Codex 存),归一化时会体现这种不对称。
- `search_conversations` 的正文扫描有数量上限(默认 60 个会话)以控制开销;标题命中不受限。
- Cursor 读取依赖 Node 内置 `node:sqlite`(需 **Node ≥ 22.13**,本机 Node 24 直接可用;旧版本上 cursor 来源会被报为不可用而非报错)。读取时把 `state.vscdb` 连同 `-wal`/`-shm` 一起拷到**私有临时目录**(0600 权限、进程退出即删),以只读方式打开;副本含 `cursorAuth/*` 令牌,故不落在共享 `/tmp`、用完即清。
- 摘要器是**确定性抽取式**,不调 LLM:目标取首条用户消息、已完成取工具调用、卡点取报错结果、待办取工具原生 todo 列表——它不"理解"语义,只做高信噪比的结构化提取。
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: listing conversations, searching, retrieving full content, summarizing, and listing sources. No two tools overlap in functionality.
All tool names follow a consistent verb_noun pattern (list_conversations, search_conversations, get_conversation, summarize_conversation, list_sources), making them predictable and easy to understand.
With 5 tools, the server is well-scoped for its purpose of browsing and continuing past conversations. Each tool serves a necessary role without redundancy.
The tool surface covers the core workflows: listing, searching, retrieving full content, and summarizing. A delete or manage conversation tool is missing but not essential for the server's stated purpose.