内容
# memgrep
在您的编码过程中提供全局、可搜索、完全本地化的记忆,让您可以回忆起与代理的每一次聊天记录,跨越每个项目和每个工具,并提供嵌入式语义搜索,您可以将其构建到自己的应用程序中。
- **您的上下文在聊天之外仍然存在。** 代理会话会结束;您在会话中学习的内容不应被遗忘。memgrep 将 Cursor、Claude Code 和 Kiro 的聊天历史记录合并到一个记忆中,并将其返回给任何支持 MCP 的代理,在任务中途。
- **完全本地化。** 嵌入式运行在设备上,通过 [Transformers.js](https://github.com/huggingface/transformers.js)(Hugging Face 模型,ONNX/WASM)。无需 API 密钥,无需云端,无需数据离开您的机器。这很重要,因为您的聊天历史记录包含您的代码。
- **真正的架构,零服务器。** SQLite 用于记录,[hnswlib](https://github.com/yoshoku/hnswlib-node) HNSW 用于快速近似最近邻检索。一个文件夹是一个完整、可移植的内存。
## 演示

## 为什么
您三周前与代理解决了一个棘手的身份验证错误,但在另一个项目中使用了不同的编辑器。今天的代理不知道这件事曾经发生过。这些知识是存在的(您的工具在磁盘上保存了记录),但它们被隔离在每个项目、每个工具中,并且对搜索不可见。
memgrep 将这些记录转换为一个可查询的内存。您可以用自然语言提问(“我们如何修复了重构差异?”),它会找到发生该事件的对话,您或您的代理可以将整个对话拉回上下文中。
## 快速入门
```bash
npm install -g memgrep
memgrep ingest # 索引您的聊天历史记录(一次性扫描,然后增量)
memgrep recall "我们如何修复了身份验证竞争?" # 搜索内存
memgrep copy # 顶部命中 -> 剪贴板
```
需要 Node.js 18+。原生插件(hnswlib,better-sqlite3)在安装时构建。嵌入式模型(~25 MB)在第一次运行时下载;之后所有操作都是离线进行的。完整的命令列表如下。
## 代理内存
**获取内容有两种方式:** `ingest` 从您的工具(Cursor,Claude Code,Kiro)拉取聊天记录。`remember` 存储您自己编写的笔记(决策,后续行动,上下文未捕获的记录)。
**搜索和浏览:** `recall` 按含义查找聊天记录。`list` 显示存储的内容。`show` / `copy` 读取一个聊天记录。
```bash
memgrep scan [--source kiro] [--new] [--last <n>] # 列出磁盘聊天记录(* = 未被摄入)
memgrep ingest [--source cursor,claude,kiro] # 从支持的工具中摄入
memgrep ingest --pick 2,5 # 按编号摄入上次扫描的聊天记录
memgrep ingest --last [n] # 最近的 n 条聊天记录
memgrep ingest <file...> # 一个文件(自动检测格式)
memgrep remember "我们选择 X 而不是 Y,因为 Z" # 手动笔记(无需聊天记录)
memgrep list [--project <p>]
memgrep recall "<query>" [-k <n>]
memgrep show <id>
memgrep copy [id]
memgrep delete <id>
memgrep delete --all [--yes]
```
内存存储在 `~/.memgrep`(`MEMGREP_HOME` 可覆盖)。重新运行 `ingest` 是幂等的:未更改的聊天记录将被跳过,已增长的聊天记录将被替换。`scan` 然后 `--pick` 允许您在嵌入任何内容之前查看可用的内容。
支持的历史记录来源:
| 工具 | 来源 | 注意 |
| --- | --- | --- |
| Cursor | `~/.cursor/projects/*/agent-transcripts/` | 完整的用户 + 助手对话 |
| Claude Code | `~/.claude/projects/*/*.jsonl` | 完整的用户 + 助手对话 |
| Kiro IDE | Kiro `globalStorage` 工作区会话 | 用户对话和标题(助手输出存在于不透明的执行记录中) |
| Antigravity | 尚未 | 对话是加密的 protobuf(`.pb`);代理仍然可以通过 MCP 查询内存 |
| 其他 | `memgrep remember "<text>"` | 手动笔记,决策,后续行动 |
新的来源是可扩展的:实现 `TranscriptSource` 接口的两种方法,并将其传递给 `ingestTranscripts`。
### 为您的代理提供访问权限(MCP)
通过 MCP 公开内存,因此它适用于任何支持 MCP 的代理:Cursor,Claude Code,Kiro,Antigravity,Windsurf,Codex 等等。在 CLI 中摄入,任意位置调用。每个工具注册一次服务器:
```json
{
"mcpServers": {
"memgrep": {
"command": "npx",
"args": ["-y", "memgrep", "serve"]
}
}
}
```
配置位置:Cursor `~/.cursor/mcp.json`,Claude Code `claude mcp add memgrep -- npx -y memgrep serve`,Kiro `~/.kiro/settings/mcp.json`,Antigravity 通过其 MCP 设置 UI。
代理获得三个工具:`recall(query)`,`get_chat(id)` 和 `list_chats(project?)`。检索查找相关的聊天记录;代理将整个聊天记录拉入上下文。Kiro 中的代理可以回忆起上个月 Cursor 聊天记录中的修复程序。
## 文件搜索
对任何文件夹进行语义 grep,完全离线:
```bash
npx memgrep index ./docs
npx memgrep search "如何配置身份验证?"
```
```text
docs/authentication.md (分数 0.712)
通过在环境中设置 AUTH_SECRET 来配置身份验证,...
```
选项:`--out` / `--index` 选择索引目录(默认为 `.memgrep`),`--model` 选择任何 [Transformers.js 兼容的嵌入模型](https://huggingface.co/models?library=transformers.js&pipeline_tag=feature-extraction),`-k` 指定结果数量。
## 库使用
相同的引擎可用作可嵌入的库。就像 SQLite 用于语义搜索:不是数据库服务器,不需要 API,不需要订阅。
```typescript
import { VectorIndex } from 'memgrep';
// 首次使用时下载模型,随后缓存。
const index = await VectorIndex.create({ model: 'Xenova/all-MiniLM-L6-v2' });
await index.add([
{ id: 'doc1', text: '要重置密码,请单击忘记密码链接。' },
{ id: 'doc2', text: '我们的退款政策允许在 30 天内退货。',metadata: { url: '/refunds' } },
]);
const hits = await index.search('我忘记了登录密码,', { k: 5 });
// [{ id: 'doc1', score: 0.62, chunk: '要重置密码...', chunkIndex: 0 }]
await index.save('./my-index'); // 持久化
const loaded = await VectorIndex.load('./my-index'); // 稍后重新加载
```
长文档自动分成重叠的块(可通过 `chunkSize` / `chunkOverlap` 配置);`search` 返回每个文档的最佳匹配块。`remove(id)` 删除文档,重新 `add` 现有 id 替换它。
| 方法 | 描述 |
| --- | --- |
| `VectorIndex.create(options?)` | 新的空索引。选项:`model`, `chunkSize`, `chunkOverlap`, `initialCapacity`。 |
| `VectorIndex.load(dir)` | 加载保存的索引。 |
| `index.add(doc \| docs)` | 添加或替换文档(`{ id, text, metadata? }`)。 |
| `index.search(query, { k? })` | 按余弦相似度排名前 k 个文档。 |
| `index.remove(id)` | 删除文档。 |
| `index.save(dir)` | 持久化到目录。 |
| `index.size` | 文档数量。 |
内存层也被导出:`MemoryStore`,`ingestTranscripts` 和每个工具的解析器。
## 使用您自己的数据库
如果您已经有一个向量数据库(pgvector,Supabase,LanceDB,Qdrant),您可以使用 memgrep 纯粹作为本地嵌入管道,并跳过内置索引。`Embedder` 和 `chunkText` 被导出用于此目的:分段您的文本,在设备上嵌入它,并将向量存储在您喜欢的任何地方。
```typescript
import { Embedder, chunkText } from 'memgrep';
import pg from 'pg';
const embedder = await Embedder.create('Xenova/all-MiniLM-L6-v2');
const db = new pg.Pool();
// 索引:分段,本地嵌入,插入 pgvector。
const chunks = chunkText(article.body);
const vectors = await embedder.embed(chunks);
for (let i = 0; i < chunks.length; i++) {
await db.query(
'INSERT INTO chunks (article_id, chunk_index, text, embedding) VALUES ($1, $2, $3, $4)',
[article.id, i, chunks[i], JSON.stringify(vectors[i])],
);
}
// 搜索:以相同的方式嵌入查询,让数据库排名。
const queryVector = await embedder.embedOne('如何退款?');
const { rows } = await db.query(
'SELECT text, 1 - (embedding <=> $1) AS score FROM chunks ORDER BY embedding <=> $1 LIMIT 5',
[JSON.stringify(queryVector)],
);
```
向量是 L2 归一化的,因此余弦距离(pgvector 的 `<=>`)是正确的运算符。`embedder.dimensions` 告诉您模式的列大小(默认模型为 384)。有一条规则:始终使用与索引相同的模型嵌入查询。
## 工作原理
思维模型:**分段是搜索的对象,聊天记录是返回的内容。**
1. 聊天记录被解析为干净的 `User:/Assistant:` 对话。工具输出、差异和系统上下文被剥离;只保留对话。
2. 文本在段落/句子边界(~1000 字符,200 重叠)处分段,每个分段本地嵌入到 384 维向量(Transformers.js,均值池化,L2 归一化)。标题、项目和日期存储为普通列,不嵌入。
3. 向量进入 HNSW 索引(余弦空间);聊天记录和分段文本存储在 SQLite 中。
4. 查询以相同的方式嵌入,检索最近的分段(过度检索 4 倍,重复排除到最佳分段),结果返回分数和匹配段落。
5. 摄入根据内容哈希幂等;`remember` 和 `ingest` 都进入同一个可搜索内存。
可靠性:SQLite 是事实来源,向量索引是可重建的缓存。如果进程在摄入过程中死亡(Ctrl-C、崩溃、断电),不会丢失聊天记录:下一个需要向量的命令(`recall`、`ingest`、`serve`)检测到差异,重新嵌入缺少的内容,并修复索引,同时打印进度。不会触及向量的命令(`list`、`show`、`copy`、`delete`、`scan`)跳过修复,保持快速。
## 限制
- **精确标识符是语义搜索的弱点。** “merchant 7712” 通过周围单词的含义匹配,而不是字面字符串。混合关键词提升功能正在路线图中。
- **Kiro 摄入是部分的**(用户对话和标题;助手输出存在于不透明的执行记录中)。**Antigravity 无法摄入**(加密的 protobuf),尽管其代理仍然可以通过 MCP 查询内存。为两者提供的逃生舱口:导出或粘贴到文件中,然后 `memgrep ingest <file>`。
- **`delete` 对重新摄入不是永久的。** 如果源聊天记录仍然存在于磁盘上,下一次扫描将重新添加它。删除聊天记录或不要扫描该源。
- **一次只有一个写入者。** 并发 memgrep 进程可以在索引文件上竞争;自我修复会在下一次打开时修复任何损失,但尚无跨进程锁定。
- **召回质量跟踪已说的内容。** 会话中如果信号存在于工具输出(已剥离)中,则搜索效果较差。手动 `memgrep remember` 用自己的话通常是您存储的最有价值的信息。
## 路线图
- 混合搜索(精确 ID 和错误字符串的关键词/BM25 提升)
- 删除后 `delete` 生存的墓碑
- 更多来源(Antigravity 如果其格式开放,Codex CLI,Windsurf)
- 监视模式/后台守护进程用于连续摄入
- 通过 WASM HNSW 索引为库提供浏览器支持
## 开发
```bash
npm install
npm run build # 编译 TypeScript
npm test # 单元测试 + 集成测试(第一次运行会下载模型)
```
## 许可证
[MIT](LICENSE)