shared-memory
README.md
# shared-memory
> 一个独立、零桥依赖的 MCP 服务器:让多个 Agent(Claude Code / Codex / DSH / 任意 MCP 客户端)跨会话、跨进程共享三种记忆。
**价值主张**:给拥有一群 AI Agent 的团队一块「共享大脑」——键值记忆、时间线笔记、语义记忆,三种粒度、一次挂载、跨工具复用。
---
## 目录
- [核心特性](#核心特性)
- [三种记忆](#三种记忆)
- [安装](#安装)
- [挂载到 Claude Code](#挂载到-claude-code)
- [挂载到 Codex](#挂载到-codex)
- [工具速查(12 个)](#工具速查12-个)
- [配置项](#配置项)
- [架构](#架构)
- [快速示例](#快速示例)
- [可选:向量层](#可选向量层)
- [许可证](#许可证)
---
## 核心特性
- **零三方依赖的核心**:KV 与笔记仅使用 Node.js 标准库,开箱即用。
- **三种记忆**:KV 键值、append-only 时间线笔记、向量语义记忆(可选)。
- **跨会话 / 跨进程**:数据落盘,任何 Agent、任何 MCP 客户端读写同一份状态。
- **懒加载向量层**:未安装向量运行时(`onnxruntime-node` / `sqlite-vec`)时,纯文本 / KV / 笔记功能完整可用,绝不拖慢启动。
- **作用域分层**:`global` → `platform:<name>` → `project:<name>` 三级隔离 + 前缀匹配检索,项目知识可复用、可提级。
- **安全第一**:向量库写入前自愈(防坏库静默吞数据)、删除必须显式给条件(杜绝全表误删)、提级默认 `dry_run` 预览。
---
## 三种记忆
| 记忆 | 工具前缀 | 存储 | 用途 |
| --- | --- | --- | --- |
| **KV 键值记忆** | `shared_memory_*` | `kv.json`(JSON 原子写,最后写赢) | 轻量键值对、feature flag、跨 Agent 变量 |
| **共享笔记时间线** | `shared_notes_*` | `notes.log`(`O_APPEND` 追加) | handoff、决策记录、事件流水 |
| **向量语义记忆** | `memory_*` | `vec.db`(sqlite-vec KNN + 384 维 embedding) | 按「含义」而非「关键词」找回跨 Agent 经验 / 结论 |
---
## 安装
核心仅需 Node.js(`node:sqlite` 要求 ≥ Node 22.5,故向量层需 22.5+;KV / 笔记层 Node 20 即完整可用)。
### DSH 原生安装(dsh plugin add)
本包声明了 `dsh.bundle` manifest,可作 DeepSeek Harness 原生插件一键安装(工具以 `mcp__shared-memory__*` 前缀出现在会话中):
```bash
dsh plugin add agent-shared-memory
```
安装后重启 DSH 生效。也可以在 [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 社区列表中发现本插件。
### 一键安装(推荐)
```bash
node bin/install.mjs --list # 列出支持平台 + 已装 CLI
node bin/install.mjs --target claude # 装到 Claude Code
node bin/install.mjs --target all # 装到所有已检测到的 CLI
node bin/install.mjs --target claude --dry-run # 只预览,不落盘
node bin/install.mjs --target claude --bootstrap-vector
```
安装器优先调用官方 `<cli> mcp add`,失败回退**幂等合并**配置文件,绝不整体重写你已有的 MCP 条目(写入前自动备份 `.bak`)。支持 `claude / codex / qwen / opencode / cursor / windsurf / vscode / gemini / claude-desktop / manual`。
### 挂载到 Claude Code
在项目根目录(或 `~/.claude.json` / `claude_desktop_config.json`)中加入:
```json
{
"mcpServers": {
"shared-memory": {
"command": "node",
"args": ["<PATH-TO-PLUGIN>/src/shared-memory-server.mjs"],
"env": {
"SHARED_MEMORY_DIR": "<YOUR_SHARED_DIR>"
}
}
}
}
```
### 挂载到 Codex
在 `config.toml` 中加入:
```toml
[mcp_servers.shared-memory]
command = "node"
args = ["<PATH-TO-PLUGIN>/src/shared-memory-server.mjs"]
[mcp_servers.shared-memory.env]
SHARED_MEMORY_DIR = "<YOUR_SHARED_DIR>"
```
> 任何遵循 MCP stdio 协议的客户端(DSH 等)均可通过相同方式挂载;完整对照见 [`adapters/manual-install/README.md`](adapters/manual-install/README.md) 与 [`docs/install.md`](docs/install.md)。
---
## 工具速查(12 个)
### KV 键值记忆
| 工具 | 参数 | 说明 |
| --- | --- | --- |
| `shared_memory_set` | `key`, `value` | 写入 / 覆盖一个键值对,对所有 Agent 可见 |
| `shared_memory_get` | `key` | 按键读取;不存在返回空字符串 |
| `shared_memory_list` | — | 列出当前全部键 |
| `shared_memory_delete` | `key` | 删除键;返回移除结果(不存在则 `ok=false`) |
### 共享笔记时间线
| 工具 | 参数 | 说明 |
| --- | --- | --- |
| `shared_notes_append` | `note`, `tag?` | 追加一条带时间戳的笔记(append-only)。`tag` 用 `handoff:<id>` 分组 |
| `shared_notes_read` | `tag?` | 读取笔记,可选按 tag 过滤 |
### 向量语义记忆(可选向量层)
| 工具 | 参数 | 说明 |
| --- | --- | --- |
| `memory_add` | `content`, `category?`, `source?`, `scope?`, `cwd?` | 存入一条带 384 维 embedding 的记忆;category 自动构造为 `<scope>:<platform>:general` |
| `memory_search` | `query`, `top_k?`, `category?`, `scope?`, `cwd?`, `min_length?` | 语义检索,按余弦相似度返回 top-k;带分层保底配额 |
| `memory_list` | `category?`, `category_prefix?`, `limit?`, `offset?` | 列出记忆(不含向量),按 category 精确 / 前缀过滤 + 分页 |
| `memory_delete` | `id?`, `category?`, `category_prefix?` | 按 id 单删 / 按 category 或前缀批删;幂等,无匹配即 0 |
| `memory_stats` | — | 统计:总数、按 category 分组、embedding 维度、模型路径 |
| `memory_promote` | `id`, `to_scope`, `dry_run?` | 手动把记忆提级到更宽的 scope(如 `project` → `global`);`dry_run` 默认 `true` 仅预览 |
> `memory_*` 工具与实际 backend 名(`vec_memory.mjs` 导出)一一对应,命名保持一致,便于调试定位。
---
## 配置项
| 环境变量 | 默认值 | 说明 |
| --- | --- | --- |
| `SHARED_MEMORY_DIR` | `~/.agents/shared-memory/` | KV 与笔记所在目录(与 multi-agent bridge 共用) |
| `SHARED_MEMORY_FILE` | `<DIR>/kv.json` | KV 存储文件 |
| `SHARED_NOTES_FILE` | `<DIR>/notes.log` | 笔记时间线文件 |
| `VECTOR_DIR` | `~/.agents/vector` | 向量层目录(模型 + 数据库 + 原生库) |
| `VECTOR_DB` | `<DIR>/vec.db` | sqlite-vec 数据库 |
| `VECTOR_MODEL` | `<DIR>/model-multilingual/model_quantized.onnx` | 量化 ONNX 模型路径 |
| `VECTOR_TOK` | `<DIR>/model-multilingual/tokenizer.json` | BERT WordPiece 分词器词表 |
| `VEC0_LIB` | `<DIR>/vec0.{so,dll}` | sqlite-vec 原生扩展库(按平台选扩展名) |
| `VECTOR_WORK_ROOT` | `~/work` | 从 `cwd` 推断 project name 时的工作副本根 |
> `VEC0_SO` 为旧名,仍被兼容;`VEC0_LIB` 优先。
---
## 架构
```
┌──────────────────────────────────┐
MCP 客户端 │ src/shared-memory-server.mjs │
(Claude/Codex/DSH) │ stdio JSON-RPC (2024-11-05) │
────────────────────▶│ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ KV 层 │ │ 笔记层 │ │
│ │ kv.json │ │ notes.log │ │
│ │ 原子写/末写 │ │ O_APPEND │ │
│ └────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ 向量层 vec_memory.mjs (懒加载)│ │
│ │ onnxruntime-node → 384 维 │ │
│ │ node:sqlite + vec0 KNN │ │
│ │ BertTokenizer (手写 WordPiece)│ │
│ └─────────────────────────────┘ │
└──────────────────────────────────┘
```
- **传输**:标准 `stdio` + 每行一条 JSON-RPC;每个客户端连接一个实例,多实例并发写 KV 为「最后写赢」语义。
- **懒加载**:模块加载时不初始化 ONNX / sqlite,首次调用 `memory_*` 才建会话,避免无关调用时占内存、拖慢启动。
- **作用域分层**:category 形如 `<scope>:<platform>:<domain>`,检索时按 `global:`、`platform:<猜>:`、`project:<name>:` 前缀集合做逻辑隔离,自动从 cwd 或内容关键词发现项目平台归属。
- **自愈与并发**:向量库开启 WAL + `busy_timeout`,跨进程读者不被写者阻塞;打开前 `_doctorDb()` 校验 SQLite magic,坏库先备份重建,绝不静默覆盖。
- **分词兼容**:内置 BERT WordPiece 分词器,兼容经典 MiniLM 词表与句法分词多语言词表两种形状;CJK 自动加边界空格。
---
## 快速示例
**1) Agent A 存一个约定:**
```
tools/call shared_memory_set { key: "released_android_api", value: "34" }
```
**2) Agent B 读它:**
```
tools/call shared_memory_get { key: "released_android_api" }
→ 34
```
**3) 记录一次 handoff:**
```
tools/call shared_notes_append { note: "已定位到崩溃根因,交由负向 Agent 复现", tag: "handoff:crash-9f" }
```
**4) 需要交接时读回:**
```
tools/call shared_notes_read { tag: "handoff:crash-9f" }
```
**5) 沉淀一条语义记忆供日后按含义找回:**
```
tools/call memory_add {
content: "启用 WAL + busy_timeout 后,多进程并发写 SQLite 不再报 database is locked",
source: "agent:debug-session"
}
```
**6) 语义检索(跨关键词匹配):**
```
tools/call memory_search { query: "并发写库锁表怎么解决", top_k: 5 }
→ [global:general] d=0.184 (src:agent:debug-session)
启用 WAL + busy_timeout 后,多进程并发写 SQLite 不再报 database is locked
```
**7) 把某项目经验提级为全局公共知识(先预览):**
```
tools/call memory_promote { id: 42, to_scope: "global" } # dry_run 默认 true,仅预览
tools/call memory_promote { id: 42, to_scope: "global", dry_run: false } # 确认后真改
```
---
## 可选:向量层
向量层让 `memory_*` 工具具备语义检索能力。未安装时这些工具返回「vector layer not initialized」,**其余功能不受影响**。
### 依赖
- `onnxruntime-node` - 运行量化 ONNX 模型(`paraphrase-multilingual-MiniLM-L12-v2`,384 维,中文检索效果优于英文版;英文原版 MiniLM 仍可回退)
- `node:sqlite`(内置)+ `sqlite-vec` 扩展 `vec0`(Linux 为 `vec0.so`,Windows 为 `vec0.dll`)
### 安装步骤
1. 准备模型与矢量扩展,放入 `VECTOR_DIR`(默认 `~/.agents/vector`):
- 模型:`model-multilingual/model_quantized.onnx` + `model-multilingual/tokenizer.json`
- 原生库:`vec0.so`(或 `vec0.dll`),或用 `VEC0_LIB` 指定路径
2. 安装运行时依赖:
```bash
npm i onnxruntime-node
```
3. 通过环境变量指到你的路径(如非默认布局):
```bash
VECTOR_DIR=<YOUR_VECTOR_DIR> \
VECTOR_MODEL=<path-to-model_quantized.onnx> \
VECTOR_TOK=<path-to-tokenizer.json> \
VEC0_LIB=<path-to-vec0.so> \
node src/shared-memory-server.mjs
```
4. 自检:调用 `memory_stats` 应返回 `count`、`dim=384`、按 category 的分组统计。
> **平台提示**:Linux 上 `onnxruntime-node` 在个别发行版可能有原生库兼容差异;若启动报符号缺失,请参阅 onnxruntime 官方文档。
---
## 目录结构
```
shared-memory/
├── src/ # 平台无关核心(零依赖)
│ ├── shared-memory-server.mjs # MCP server(12 工具,stdio)
│ └── vec_memory.mjs # 向量层(懒加载 node:sqlite + onnxruntime)
├── bin/install.mjs # 统一 CLI 安装器(--target/--list/--dry-run/--bootstrap-vector/--uninstall)
├── adapters/ # 各平台挂载模板 + 手抄指引
├── marketplace/ # 插件市场清单
├── install/ # 一键装 bootstrap 壳(.sh / .ps1)
├── docs/ # install.md + tools.md
├── skills/ # 技能(shared-memory/SKILL.md,随包分发)
├── .github/workflows/ # CI(语法 + npm pack --dry-run + install smoke)
├── package.json # 双 bin + files 白名单 + engines >=20
└── LICENSE / README.md / README_EN.md
```
---
## 许可证
[MIT](LICENSE)This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues