内容
# mnemos
[](https://github.com/arhuman/mnemos/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/arhuman/mnemos)
[](https://github.com/arhuman/mnemos/releases)
[](go.mod)
[](LICENSE)
### 给你的 AI 代理一个可以引用的记忆。
**mnemos** 是一个本地优先的 AI 代理内存,以单个 Go 二进制文件交付。
它索引你的项目笔记、文档、ADRs、源代码和 OKF 知识库,然后通过 [MCP](https://modelcontextprotocol.io) 公开它们,以便 Claude Code(或任何 MCP 客户端)可以**搜索、读取和引用你自己的知识**,而无需外部服务(无 Ollama、Qdrant、Chroma、Python、Node 或强制 Docker)。
<p align="center">
<img src="docs/demo.gif" alt="mnemos CLI: init, ingest, and a search that returns a cited result" width="760">
</p>
## 为什么选择 mnemos
- **真正本地优先**:完全在你的机器上运行。无需网络,无需遥测,无数据离开你的项目。
- **零依赖**:一个自包含的、无 cgo 的 Go 二进制文件。无需 Python、Docker、Qdrant 或 Ollama。
- **任何 MCP 客户端**:为 Claude Code 构建,与任何支持 MCP 的客户端兼容。
- **引用答案**:每个结果都链接回确切的 `file#section` 和行范围,因此声明是可验证的。
- **默认快速搜索**:SQLite FTS5 / bm25 开箱即用;可选的本地语义 + 混合搜索位于构建标签后。
- **读写内存**:代理可以捕获持久性笔记(`remember`);你可以管理树(`forget`、`move`、`list`)。
- **默认安全**:只读,除非你选择加入;写入路径受限,内容经过秘密扫描。
## 它是如何工作的
```text
你的文件 → mnemos 索引(SQLite/FTS5) → Claude Code 内存 → 引用答案
```
一旦连接,Claude 就可以从你的项目中回答问题,而不是凭空猜测,并指向源头:
- *"为什么我们选择这种架构?*"
- *"ADR 关于规则引擎的文档在哪里?*"
- *"总结我们对 SCIM 配置文件的了解。"*
- *"这个项目的内存最近发生了什么变化?*"
在幕后,二进制文件嵌入了一个 MCP 服务器、索引管道、SQLite 存储、全文本搜索、增量文件监视器和管理员 CLI。参见
[docs/architecture.md](docs/architecture.md)。
## 安装
```bash
git clone https://github.com/arhuman/mnemos.git && cd mnemos
make install # 构建一个无 cgo 的二进制文件到 $GOBIN
# 或:make build # -> ./bin/mnemos
```
需要 Go 1.25+。默认构建是**纯 Go / 无 cgo**(`make build` 设置 `CGO_ENABLED=0`)。
## 快速开始
```bash
cd ~/work/myproject
mnemos init # 创建 ./.mnemos.toml + ./.mnemos/
mnemos ingest docs --collection myproject # 索引目录
mnemos search "规则引擎" # 从 CLI 查询
```
`search` 打印引用:
```text
1. security/scim.md#Provisioning
行 42-88
评分 12.7
```
引用使用**相对于扫描根目录**的路径(此处为 `docs`),而不是你的工作目录。
> ⚠️ **注意 URI 问题。** 文档的身份是其路径**相对于你运行 `ingest` 的位置**。索引两个包含相同文件(例如 `index.md`)的目录会解析为相同的 URI:**第二个索引会静默覆盖第一个索引**。要干净地索引多个树,请从一个公共根目录索引(`mnemos ingest .`)。详细信息参见 [docs/paths-and-indexing.md](docs/paths-and-indexing.md)。
## 连接 Claude Code
使用**绝对 `--config`** 路径注册 MCP 服务器:
```bash
claude mcp add mnemos -- mnemos serve --config /abs/path/to/project/.mnemos.toml
```
或使用 `.mcp.json` 将其与仓库一起提交:
```json
{ "mcpServers": { "mnemos": { "command": "mnemos", "args": ["serve", "--config", "/abs/path/to/project/.mnemos.toml"] } } }
```
使用 `claude mcp list` 验证(应显示 `mnemos ✓ connected`)和 `/mcp` 在会话内。Claude 然后自动调用工具;参见[功能](#功能)。
<details>
<summary>为什么 <code>--config</code> 路径必须是绝对路径</summary>
Claude Code 不保证它启动服务器的工作目录,因此锚定到配置文件是检索可靠的方法。`mnemos serve` 将相对 `[storage].path` 解析为配置文件目录的路径,因此绝对 `--config` 就足够了:数据库、捕获目录和树根都锚定在该文件旁边,无论 Claude Code 启动服务器的位置。裸 `mnemos serve` 仅在服务器的工作目录恰好是项目根目录时才找到你的数据,Claude Code 不承诺这一点;当数据库无法找到时,`serve` 失败并显示明确的错误信息,而不是静默返回空结果。
</details>
<p align="center">
<img src="docs/demo-mcp.gif" alt="Registering mnemos as an MCP server; Claude Code reports it connected" width="760">
<br><em>一条命令连接它:Claude Code 报告 <code>mnemos ✓ connected</code>。</em>
</p>
<p align="center">
<img src="docs/demo-session.gif" alt="Claude Code answering a question from mnemos memory, with a file#section citation" width="760">
<br><em>Claude 从内存中回答并跳转到 <code>file#section</code> 源。</em>
</p>
### 让 Claude 自动使用内存(可选技能)
MCP 工具是**被动的**:它们可用,但 Claude 仍必须决定在回答之前调用 `mnemos.search` 或在说出某些值得保留的内容时调用 `mnemos.remember`,而模型通常不会这样做。捆绑的 **`mnemos-okf` 技能** 弥补了这一空白,通过编码**何时**访问内存:从假设中回忆,在回答之前,从捕获持久事实,并驱动 OKF 工具。
它是可选的,特定于 Claude Code:服务器与任何 MCP 客户端一起工作,但无需它。全局安装(所有项目):
```bash
make install-skill # 复制 skills/mnemos-okf -> ~/.claude/skills/
```
或手动放置,例如仅限于此仓库的项目级:
```bash
mkdir -p .claude/skills && cp -r skills/mnemos-okf .claude/skills/mnemos-okf
```
捕获故意保守(仅持久事实,秘密扫描),并在 `allow_write`/`allow_delete` 未启用时保持开启:技能从不授予对配置未启用的访问权限。参见 [`skills/mnemos-okf/SKILL.md`](skills/mnemos-okf/SKILL.md)。
## 功能
Claude 通过 MCP 工具(和匹配的 CLI 命令)访问你的内存。注意拼写:`mnemos.search` 是 **MCP 工具**,Claude 调用;`mnemos search` 是 **CLI 命令**,你运行。
### 查询(只读,无门控)
- **`mnemos.search`**: 排名过滤检索,附有引用。
- **`mnemos.read`**: 读取精确的块(按 `chunk_id`)或整个文档(按 `uri`)。
- **`mnemos.context`**: 顶级结果作为 LLM 就绪的上下文块(`uri:start-end` → 内容)。
- **`mnemos.list`**: 在磁盘上遍历 OKF 树,并用索引元数据注释每个文件(标题、类型、标签、集合)以及 `indexed` 标志,以便可见存储和未索引的文件。按 `path`、`collection`、`type` 或索引状态过滤。
### 写入(需要 `allow_write = true`)
- **`mnemos.remember`**: 将笔记写入内存。传递可选的 `path`(例如 `"adr/0003-rule-engine.md"`),将其放在 OKF 树中的显式位置,而不是在 `[capture].dir` 下自动命名。内容在写入和索引之前会进行**秘密扫描**。
- **`mnemos.okfy`**: 将树中现有的 `.txt`/`.md` 文件转换为 OKF 文档(前置 + 正文)到 `out`(默认为源路径,带有 `.md` 扩展名),并索引它,源文件保持完整。源正文会进行**秘密扫描**。
### 管理(需要 `allow_delete = true`)
- **`mnemos.forget`**: 从 OKF 树中删除文件并取消索引;幂等。
- **`mnemos.move`**: 在树内移动文件**或目录**并在新路径下重新索引。目录移动其整个子树,保留每个文档的集合。V0 中的 Markdown 链接到旧路径不会被重写(记录为警告)。
## 保持内存新鲜
运行监视器以更改时重新索引(增量;删除的文件):
```bash
mnemos watch . --collection myproject
```
在 `.mnemos.toml` 中启用写回功能,以便 Claude 可以捕获和管理笔记:
```toml
[mcp]
allow_write = true # 控制 mnemos.remember 和 mnemos.okfy
allow_delete = true # 控制 mnemos.forget 和 mnemos.move
```
如果监视器正在遍历树,则 `forget`/`move` 操作也会被监视器看到(冗余但幂等);工具直接更新索引并工作,无需监视器。设置 `[capture] defer_to_watcher = true`,当监视器覆盖 `capture_dir` 以避免双重索引已记住的笔记。
## 语义搜索(可选)
默认二进制文件**仅限词汇**(FTS5 / bm25)且保持小巧,无 cgo 依赖。本地语义 + 混合检索功能已完全实现,但编译在 `embed` 构建标签后,因此 ONNX/tokenizer 依赖项从不进入默认二进制文件。要启用它:
```bash
make build-embed # 或:make install-embed (仍无 cgo,CGO_ENABLED=0)
mnemos models install # 将嵌入式模型下载到 ~/.mnemos/models
mnemos reindex --embeddings # 为已索引的块计算向量
mnemos search "为什么我们选择这种架构" --semantic
```
`--semantic` 将 bm25 与向量相似性相结合,因此自然语言查询会解析为词典索引无法匹配的内容。无嵌入构建(或安装的模型)时,标志被拒绝并显示明确的信息;纯 `mnemos search` 始终有效。
## OKF 支持
mnemos 原生支持 [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/tree/main/okf) (开放知识格式)包和任何带有 YAML 前置和交叉链接的 Markdown 保险库,无需特殊模式:
- 前置 `tags`/`type` 成为 FTS 中的模糊排名信号,
- Markdown 链接被捕获为边(存储,但尚未遍历),
- `index.md` 文件仅被视为结构(不参与 FTS 和链接图)。
OKF 包用作 `mnemos eval` 的语料库,它自动导出隐藏查询→源对,并报告 Hit@1 / Recall@12 / MRR@12 与提交的基线。参见 [docs/architecture.md](docs/architecture.md#retrieval-evaluation).
## 参考
<details>
<summary><strong>所有命令</strong></summary>
| 命令 | 目的 |
|---|---|
| `mnemos init` | 创建配置文件、状态目录和数据库 |
| `mnemos ingest <path> --collection <c>` | 索引文件或目录 |
| `mnemos search <query> [--collection --path --type --since --limit --semantic --json]` | 搜索索引( `--semantic` 融合词典 + 向量;需要嵌入构建) |
| `mnemos ls [path] [--collection --type --tree --depth --all --indexed --unindexed --limit --json]` | 列出/浏览 OKF 树,并用索引元数据注释 |
| `mnemos eval <okf-bundle> [--baseline <f> --save --semantic --limit N]` | 在 OKF 包上进行检索质量评估( `--semantic` 评估混合检索器) |
| `mnemos watch <path> --collection <c>` | 监视并增量重新索引 |
| `mnemos serve` | 运行 MCP 服务器(stdio) |
| `mnemos status` | 显示存储路径、计数和 FTS 可用性 |
| `mnemos version [-v]` | 打印版本; `-v` 添加提交日期、构建日期和 Go 工具链 |
| `mnemos models install` | 将嵌入式模型下载到 `~/.mnemos/models`(用于嵌入构建) |
| `mnemos reindex --embeddings` | 重新计算并存储所有块的嵌入向量 |
| `mnemos validate <bundle> [--json]` | 验证 OKF v0.1 包的一致性 |
| `mnemos task list` | 列出按状态分组的索引任务文档 |
| `mnemos forget <path>` | 从 OKF 树中删除文件并取消索引(需要 `allow_delete = true`) |
| `mnemos mv <src> <dst>` | 在 OKF 树内移动文件或目录并重新索引(需要 `allow_delete = true`) |
| `mnemos okfy <file> [--collection --type --tags --out --force]` | 将 `.txt`/`.md` 文件转换为 OKF 文档,然后索引它(源文件保持完整) |
</details>
<details>
<summary><strong>配置(<code>.mnemos.toml</code>)</strong></summary>
配置是分层的,优先级从低到高:
1. **内置默认值**(下文显示的值)。
2. **`~/.mnemos.toml`**:用户全局覆盖,应用于每个项目。
3. **`./.mnemos.toml`**:工作目录中的项目文件;其键胜过家用文件。
每个层仅覆盖它设置的键;其他一切都继承自下面的层,因此部分文件是可以的。传递 `--config <path>` **替换**此自动发现:仅使用该文件分层在默认值之上(忽略家用和项目文件),其目录成为树根。
```toml
[storage]
path = ".mnemos/mnemos.db"
[indexing]
include = ["**/*.md", "**/*.txt", "**/*.go", "**/*.sql"]
exclude = [".git/**", "node_modules/**", "vendor/**", "dist/**"]
max_file_bytes = 4194304 # 跳过任何大于此的文件(0 禁用)
[chunking]
target_tokens = 700
overlap_tokens = 80
[search]
default_limit = 12
[mcp]
transport = "stdio"
allow_write = false # 控制 mnemos.remember
allow_delete = false # 控制 mnemos.forget 和 mnemos.move
[capture]
dir = ".mnemos/capture" # 自动命名笔记的默认路径
defer_to_watcher = false # true => remember 仅写入,监视器索引
[security]
exclude_secrets = true
exclude = ["**/.env", "**/*.pem", "**/*.key", "**/id_rsa", "**/secrets/**"]
```
</details>
**路径、URI 和写入**,涵盖状态的位置、索引内容、写入位置以及幂等性/URI 规则:参见
[docs/paths-and-indexing.md](docs/paths-and-indexing.md)。
## 安全
- 无网络,无遥测;MCP 服务器仅限 stdio。
- 默认只读。写回功能需选择加入(`allow_write = true`)。破坏性操作(忘记,移动)需要单独选择加入(`allow_delete = true`)。
- 所有调用者提供的路径在磁盘操作前都会经过一个隔离保护程序:拒绝 `..` 遍历、超出树根的绝对路径、符号链接逃逸、访问 `.mnemos/` 和 `[security].exclude` 通配符。
- 捕获的内容在写入或索引之前会进行秘密扫描。
- 路径/秘密排除模式保留 `.env`、密钥和秘密目录不被索引。
参见 [SECURITY.md](SECURITY.md) 以获取完整的安全策略。
## 开发
```bash
make build # 无 cgo 二进制文件 -> bin/
make test # go test -race ./...
make audit # golangci-lint (包括 govet + staticcheck)+ govulncheck + 赛车测试
make tools # 安装固定开发工具(golangci-lint, govulncheck)
make help # 列出所有目标
```
架构、设计原则和检索评估方法论位于
[docs/architecture.md](docs/architecture.md);设计决策记录为
[ADRs](docs/adr/)。欢迎贡献;参见 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 许可证
mnemos 在 [MIT License](LICENSE) 下许可:这涵盖了 mnemos 自己的代码和内容。存储库还提供了第三方材料,这些材料**不**受 MIT License 覆盖,仍然在其自身条款下;见
[THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md)(尤其是在 `examples/onpage-seo/bundle/` 中的示例 OKF 包)。</content>