379 lines
19 KiB
Markdown
379 lines
19 KiB
Markdown
# MemRelay
|
||
|
||
MemRelay 是一个自托管的 AI 记忆、开发历史、密码库接入和文件仓储服务。它让 Codex、Cursor、Claude Code、VS Code 等客户端在不同设备、项目和聊天窗口之间恢复上下文,并在开发过程中持续写入规则、决定、经验、凭证和检查点。
|
||
|
||
外部 AI 整理和记忆 Git 都是独立的可选增强,默认关闭。两者都不配置时,MemRelay 不探测模型、不创建整理或 Git 任务、不初始化 `.git`,现有记忆、项目、搜索、密码库、文件、Web 和 MCP 能力保持正常可用。
|
||
|
||
MemRelay 面向个人和私有团队部署。Web、REST 与 Streamable HTTP MCP 共用同一套能力,配置一次后即可由 AI 客户端持续使用。
|
||
|
||
## 核心能力
|
||
|
||
- 全局规则与偏好,以及按项目组织的事实、决定、经验和开发检查点。
|
||
- 通过 Git remote、项目名称和多设备目录别名识别同一个项目。
|
||
- 秒级开发时间线,记录完成内容、原因、关键修改、验证、问题与解决方案和下一步。
|
||
- Basic Memory Markdown 正文、全文搜索和本地多语言语义搜索。
|
||
- 连接已有 Vaultwarden/Bitwarden,完整管理账号、密码、URI、Token、自定义字段和 TOTP。
|
||
- 带目录、说明、版本、标签、一次性上传、签名下载和 HTTP Range 的文件仓储。
|
||
- 项目文档 ZIP 直接下载到 `aidocs/`,避免 AI 逐条读取并重写而消耗 Token。
|
||
- 可取回、撤销的只读或读写 MCP Token,以及主流 AI 客户端配置生成。
|
||
- 中文默认、可切换英文的桌面 Web 界面。
|
||
|
||
## 系统架构
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
AI["Codex / Cursor / Claude Code / VS Code"] -->|"Streamable HTTP MCP"| MCP["MemRelay MCP"]
|
||
WEB["Desktop Web"] -->|"REST / Session"| API["MemRelay API"]
|
||
MCP --> CORE["Project, Memory, Vault, File Services"]
|
||
API --> CORE
|
||
CORE --> CURATION["Optional Curation Worker"]
|
||
CURATION -.-> MODEL_API["OpenAI-compatible API"]
|
||
CURATION --> SOURCE["Memory, Files, Agent Sources, Read-only Git"]
|
||
CORE --> MEMORY_GIT["Optional Memory Git"]
|
||
MEMORY_GIT -.-> GIT_REMOTE["User-provided Git Remote"]
|
||
CORE --> DB[("SQLite metadata")]
|
||
CORE --> BM["Basic Memory"]
|
||
BM --> MD[("Markdown notes")]
|
||
BM --> MODEL["Local multilingual MiniLM"]
|
||
CORE --> BW["External Vaultwarden / Bitwarden"]
|
||
CORE --> FILES[("File repository")]
|
||
```
|
||
|
||
数据关系:
|
||
|
||
```mermaid
|
||
erDiagram
|
||
PROJECT ||--o{ PROJECT_ALIAS : identifies
|
||
PROJECT ||--o{ MEMORY_REFERENCE : owns
|
||
PROJECT ||--o{ FILE_RECORD : relates
|
||
MEMORY_REFERENCE }o--|| BASIC_MEMORY_NOTE : points_to
|
||
MCP_TOKEN }o--|| ADMINISTRATOR : managed_by
|
||
VAULT_CONNECTION ||--o{ CREDENTIAL_MAPPING : resolves
|
||
FILE_RECORD ||--o{ UPLOAD_TASK : receives
|
||
USAGE_PROFILE ||--o{ MEMORY_REFERENCE : scopes
|
||
PROJECT ||--o{ CURATED_DOCUMENT : organizes
|
||
CURATION_JOB ||--o{ CURATION_ATTEMPT : runs
|
||
GIT_CONNECTION ||--o{ MEMORY_REPOSITORY : manages
|
||
MEMORY_REPOSITORY ||--o{ GIT_SYNC_JOB : queues
|
||
```
|
||
|
||
一次完整 AI 会话:
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant AI as AI Client
|
||
participant MCP as MemRelay MCP
|
||
participant MR as MemRelay Core
|
||
participant BM as Basic Memory
|
||
participant VW as Vaultwarden
|
||
participant FS as File Repository
|
||
|
||
AI->>MCP: capabilities_get
|
||
AI->>MCP: project_resolve_or_create(directory, git_remote, name)
|
||
AI->>MCP: context_get + checkpoint_get
|
||
MCP->>BM: Read global and project Markdown
|
||
BM-->>AI: Rules, facts, decisions, experience, progress
|
||
loop During development
|
||
AI->>MCP: memory_save
|
||
AI->>MCP: secret_search / secret_save
|
||
MCP->>VW: Read or update reusable credentials
|
||
AI->>MCP: file_upload_prepare / file tools
|
||
MCP->>FS: Store artifacts and metadata
|
||
end
|
||
AI->>MCP: checkpoint_save
|
||
MCP->>BM: Append structured development history
|
||
opt AI curation enabled
|
||
AI->>MCP: curation_source_submit
|
||
MCP->>MR: Queue bounded incremental curation
|
||
MR->>BM: Apply revisioned curated documents
|
||
end
|
||
opt Memory Git enabled
|
||
MR->>MR: Queue and commit the logical memory change
|
||
end
|
||
opt Local aidocs required
|
||
AI->>MCP: project_export_prepare
|
||
MCP-->>AI: Signed ZIP URL and extraction command
|
||
end
|
||
```
|
||
|
||
## 运行环境
|
||
|
||
- Windows:Docker Desktop 的 Linux 容器模式。
|
||
- Linux:Docker Engine 与 Docker Compose v2。
|
||
- 正式验证架构:`linux/amd64`、`linux/arm64`。
|
||
|
||
项目不绑定具体 CPU 型号、核心数、内存容量或 Linux 发行版。ARM64 验收在物理 Linux/Armbian 设备原生构建和运行。
|
||
|
||
## 快速部署
|
||
|
||
要求:Git、Docker、Docker Compose v2。
|
||
|
||
Linux:
|
||
|
||
```bash
|
||
git clone --recurse-submodules <repository-url> memrelay
|
||
cd memrelay
|
||
cp .env.example .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Windows PowerShell:
|
||
|
||
```powershell
|
||
git clone --recurse-submodules <repository-url> memrelay
|
||
Set-Location memrelay
|
||
Copy-Item .env.example .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
默认地址:`http://localhost:8080`
|
||
|
||
新数据目录首次启动会自动创建管理员:
|
||
|
||
- 用户名:`admin`
|
||
- 初始密码:`242520`
|
||
|
||
已有实例不会被默认值覆盖。登录后可在“系统与备份”页面修改密码。
|
||
|
||
如果仓库已经克隆但缺少子模块:
|
||
|
||
```bash
|
||
git submodule update --init --recursive
|
||
```
|
||
|
||
## 配置
|
||
|
||
编辑 `.env`:
|
||
|
||
| 变量 | 默认值 | 说明 |
|
||
| --- | --- | --- |
|
||
| `MEMRELAY_PORT` | `8080` | Web、REST 与 MCP 的宿主机端口 |
|
||
| `MEMRELAY_PUBLIC_URL` | `http://localhost:8080` | 浏览器、MCP 和签名下载使用的最终公开 URL |
|
||
| `MEMRELAY_DATA_PATH` | `./data` | 两个容器共享的持久化目录 |
|
||
| `MEMRELAY_INITIAL_ADMIN_USERNAME` | `admin` | 新实例初始管理员 |
|
||
| `MEMRELAY_INITIAL_ADMIN_PASSWORD` | `242520` | 新实例初始管理员密码 |
|
||
| `MEMRELAY_FILE_SCAN_INTERVAL_SECONDS` | `900` | 文件仓储扫描周期,`0` 关闭 |
|
||
| `MEMRELAY_VAULT_SYNC_INTERVAL_SECONDS` | `300` | 外部密码库同步周期,`0` 关闭 |
|
||
| `MEMRELAY_CONTEXT_MAX_CHARS` | `24000` | 上下文最大字符数 |
|
||
| `MEMRELAY_UPLOAD_MAX_BYTES` | `10737418240` | 单文件最大上传字节数 |
|
||
| `UID` / `GID` | `1000` | Linux 容器业务进程与数据目录属主 |
|
||
| `TZ` | `Asia/Shanghai` | 容器时区 |
|
||
| `MEMRELAY_BUILD_HTTP_PROXY` | 空 | 可选,仅用于镜像构建的 HTTP 代理 |
|
||
| `MEMRELAY_BUILD_HTTPS_PROXY` | 空 | 可选,仅用于镜像构建的 HTTPS 代理 |
|
||
| `MEMRELAY_BUILD_ALL_PROXY` | 空 | 可选,仅用于镜像构建的通用代理 |
|
||
| `MEMRELAY_BUILD_APT_MIRROR` | 空 | 可选 Debian 镜像主机,例如 `https://mirrors.aliyun.com` |
|
||
|
||
局域网可直接使用 HTTP。公网应由 Caddy、Nginx、OpenResty 或其他反向代理提供 HTTPS,并把 `MEMRELAY_PUBLIC_URL` 设置为最终 HTTPS 地址。
|
||
|
||
不要缓存 `/api/`、`/mcp`、登录、密码库、上传和签名下载响应。仅 `/assets/` 适合长期静态缓存。
|
||
|
||
1Panel OpenResty 可以使用仓库中的两份示例:
|
||
|
||
- `deploy/openresty/memrelay-cache.conf` 放入 OpenResty `http` 级配置目录,定义独立的 `memrelay_assets` 缓存区。
|
||
- `deploy/openresty/memrelay-assets.conf` 放入 MemRelay 站点的 `server` 配置或 `proxy/` 包含目录,只缓存带内容哈希的 `/assets/`。
|
||
|
||
示例中的上游为 `127.0.0.1:52001`,部署到其他端口或直接反代 MemRelay 时需要按实际地址调整。配置后先执行 `openresty -t`,成功后再热加载。首次请求应返回 `X-Cache: MISS`,后续请求返回 `X-Cache: HIT`;API 和 MCP 响应不得出现缓存命中。
|
||
|
||
## Web 使用
|
||
|
||
Web 页面包括:
|
||
|
||
- 仪表盘:项目、记忆、检查点、文件、Token、依赖状态、近 14 天新增记忆趋势、类型占比、项目排行和最近开发活动。
|
||
- 全局记忆:跨项目规则、偏好、事实和经验。
|
||
- 项目:搜索、编辑、停用、永久删除、项目记忆、开发时间线和文档下载。
|
||
- 搜索与编辑:全文、标题、混合和向量搜索,并显示所属项目。
|
||
- 项目开发时间线:按秒展示检查点,支持查看、创建、编辑和删除检查点。
|
||
- 密码库:连接、同步、列出、搜索、查看、新增、修改和删除登录条目。
|
||
- 文件仓储:目录与文件的上传、下载、移动、元数据和扫描。
|
||
- AI 整理:可选模型连接、任务、整理文档和调度;记忆空间与“全部记忆空间”Token 在 MCP Token 页面管理,未配置 AI 时保持中性关闭状态。
|
||
- 记忆版本:可选本地 Git 历史、远端同步、差异、恢复和受控仓库模式迁移;未配置时不创建 `.git`。
|
||
- MCP Token、客户端配置、Agent 提示词、运行设置和备份说明。
|
||
|
||
AI 整理会把连接超时、远端协议断开、代理断流、`408`、`429` 和 `5xx` 作为临时依赖故障处理:单次请求进行有限重试,仍不可用时任务进入 `waiting_dependency`,模型探测恢复后自动继续。长输出端点建议启用流式模式,以持续接收数据并降低反向代理空闲断开的概率;流式网络故障不会自动退回更容易被空闲超时中断的非流式请求,只有端点明确拒绝流式参数时才降级。执行输出每分钟记录长调用仍在处理的状态,完成后显示底层请求尝试次数和端到端总耗时。
|
||
|
||
Basic Memory 超时或暂时不可用只影响当前整理任务:任务按配置的有界指数退避重新排队,不会被永久标记失败,也不会把外部模型状态误判为不可用。整理 worker 会实时遵循启用状态和最大并发设置;降低并发或停用整理时,已有 worker 完成当前任务后平滑退出。服务停止会结束当前模型调用记录,服务重启会清理遗留调用并重新排队未完成任务。
|
||
|
||
已有记忆打开时 Markdown 默认进入预览,新建记忆默认进入编辑。新建记忆在正文为空时按类型提供编辑模板,支持规则、偏好、事实、决定、经验、检查点、需求文档和任务列表。项目开发时间线和导出的 `project_context.md` 均按最新在前排列,时间精确到秒。弹窗操作区固定,Markdown、预览、日志和列表在自己的区域滚动并按桌面浏览器高度自适应。
|
||
|
||
## MCP 接入
|
||
|
||
1. 在“MCP Token”页面创建读写 Token。
|
||
2. 在“客户端配置”选择 Codex、Cursor、Claude Code、VS Code 或通用客户端。
|
||
3. 使用生成的配置接入 `<MEMRELAY_PUBLIC_URL>/mcp`。
|
||
4. 在“提示词”页面复制当前语言的 Agent 工作流到项目或客户端规则文件。
|
||
|
||
支持 MCP Resource 的客户端在初始化后还应读取 `memrelay://guide` 和 `memrelay://capabilities`,以获得当前实例的可选能力状态;未配置 AI、Git 或密码库时继续使用基础记忆工作流,不需要额外配置。
|
||
|
||
`capabilities_get` 与 `memrelay://capabilities` 返回同一份实时能力清单,包含 Basic Memory/语义搜索、密码库、AI 整理和记忆 Git 的当前状态;`dashboard_get` 还返回与 Web 仪表盘一致的数据库、整理、记忆 Git 和依赖状态,客户端不需要猜测服务是否可用。
|
||
|
||
只读 Token 只能发现读取工具;读写 Token 可以使用全部项目、记忆、密码库、文件、系统和 Token 管理能力。创建 Token 时可选择具体记忆空间,或选择“全部记忆空间”;全部记忆空间 Token 自动包含之后新增的空间。撤销会让 Token 永久失效但保留记录,删除则永久移除 Token 记录。
|
||
|
||
### MCP 工具
|
||
|
||
| 分类 | 工具 |
|
||
| --- | --- |
|
||
| 能力 | `capabilities_get` |
|
||
| 项目 | `project_list`、`project_resolve`、`project_resolve_or_create`、`project_create`、`project_update`、`project_archive`、`project_delete`、`project_export_prepare` |
|
||
| 记忆 | `context_get`、`memory_list`、`memory_search`、`memory_get`、`memory_save`、`memory_mark_pending`、`memory_archive`、`memory_delete` |
|
||
| 检查点 | `checkpoint_get`、`checkpoint_save`、`checkpoint_delete` |
|
||
| 密码库 | `secret_capabilities`、`secret_sync`、`secret_list`、`secret_item_get`、`secret_search`、`secret_resolve`、`secret_get`、`secret_totp`、`secret_save`、`secret_delete` |
|
||
| 文件 | `file_list`、`file_search`、`file_get`、`file_directory_create`、`file_upload_prepare`、`file_upload_status`、`file_metadata_update`、`file_move`、`file_delete`、`file_scan` |
|
||
| AI 整理(可选) | `curation_run`、`curation_status`、`curation_history`、`curation_source_submit`、`curated_document_list/get/update/history/diff/revert`、`curation_cancel/retry`、`curation_settings_get/update`、`curation_schedule_list/save/delete/reset_defaults/preview`、`curation_model_connection_status/save/test`、`curation_model_list` |
|
||
| 记忆空间 | `usage_profile_list`、`usage_profile_save`、`usage_profile_token_bind`、`usage_profile_delete` |
|
||
| 记忆 Git(可选) | `git_connection_get/save/test/delete`、`git_mode_migration_preview/execute`、`memory_repository_list/create/status/sync/history/diff`、`memory_version_get/restore`、`memory_snapshot_restore`、`memory_repository_remote_inspect`、`memory_remote_import/bootstrap`、`memory_repository_unbind/archive_purge` |
|
||
| 系统 | `dashboard_get`、`system_settings_get`、`system_settings_update` |
|
||
| Token | `token_list`、`token_create`、`token_reveal`、`token_revoke`、`token_delete` |
|
||
|
||
MCP Resources:`memrelay://guide`、`memrelay://capabilities`、`memrelay://projects`。
|
||
|
||
`memory_search` 默认使用 `lifecycle=current`,同时返回稳定整理文档和尚未整理的新来源。结果中的 `result_kind` 和 `read_tool` 会明确指出应使用 `memory_get` 还是 `curated_document_get` 读取正文;只有追溯原始历史时才改用 `pending`、`covered`、`superseded`、`archived` 或 `all`。
|
||
|
||
失败的整理任务默认使用当前有效模型配置重试,也可以显式传入
|
||
`use_original_config=true`,复用任务保存的原模型配置 revision。整理文档支持任意两个
|
||
revision 的差异查询和以新 revision 方式回滚;调度规则可单独编辑,也可以恢复实例默认值。
|
||
|
||
## Agent 工作流
|
||
|
||
生成的提示词要求 AI 在每次新会话中:
|
||
|
||
1. 调用 `capabilities_get`。
|
||
2. 根据目录、Git remote 和名称解析项目,不存在时创建。
|
||
3. 修改代码前读取 `context_get` 和 `checkpoint_get`。
|
||
4. 过程中即时保存明确规则、偏好、事实、决定和经验。
|
||
5. 登录前先查密码库,唯一匹配直接复用;新凭证立即保存。
|
||
6. 通用文件、程序和构建产物使用文件仓储。
|
||
7. 每个有意义阶段和会话结束前保存结构化检查点。
|
||
8. 新窗口重复项目解析、上下文和检查点读取后继续工作。
|
||
|
||
启用 AI 整理后,Agent 通过 `curation_source_submit` 提交的来源在配置的新鲜度时间内优先使用;
|
||
来源过期、缺失或覆盖不足时,服务端才读取文件仓储,并在项目配置了源码 Git remote 时使用
|
||
只读 Git 工作区兜底。源码 Git 不会被整理器修改,记忆 Git 也与源码仓库相互独立。未启用 AI
|
||
或 Git 时不需要执行这些步骤,基础记忆工作流保持不变。
|
||
|
||
检查点正文应包含:
|
||
|
||
```markdown
|
||
## 完成内容
|
||
|
||
## 为什么这样做
|
||
|
||
## 关键修改
|
||
|
||
## 验证结果
|
||
|
||
## 遇到的问题与解决方案
|
||
|
||
## 下一步
|
||
|
||
## 给下个会话
|
||
```
|
||
|
||
会话结束前的最后一个检查点按交接标准书写:"下一步"和"给下个会话"要让零上下文的新会话直接接手,列出未完成线索、临时约定和需要避开的坑。
|
||
|
||
## 项目文档导出
|
||
|
||
Web 的“下载项目文档”或 MCP 的 `project_export_prepare` 会生成短期签名 ZIP,内容包括:
|
||
|
||
```text
|
||
aidocs/
|
||
project_context.md
|
||
manifest.json
|
||
curated/project/<type>.md
|
||
curated/global/<profile>/<type>.md
|
||
memories/<lifecycle>/<type>/*.md
|
||
global/sources/<lifecycle>/<type>/*.md
|
||
```
|
||
|
||
MCP 会同时返回 Windows PowerShell 和 POSIX Shell 命令。AI 应直接运行命令下载并解压到项目根目录,并确保 `.gitignore` 包含:
|
||
|
||
```gitignore
|
||
aidocs/
|
||
```
|
||
|
||
`aidocs/` 是本地上下文副本,正式写入仍通过 Web 或 MCP 完成。
|
||
|
||
## 外部密码库
|
||
|
||
MemRelay 不捆绑 Vaultwarden。请在“密码库”页面连接已有 Vaultwarden/Bitwarden:
|
||
|
||
- 注册邮箱 + 主密码。
|
||
- 个人 API 密钥 `client_id` / `client_secret` + 主密码。
|
||
- 私有网络可直接填写 HTTP 地址;公网建议填写由反向代理提供的 HTTPS 地址。
|
||
|
||
MemRelay 会持久化 Bitwarden CLI 加密状态,启动后自动登录、解锁并按周期同步。外部服务不可达时可读取最后一次成功同步的本地缓存。Web 和 MCP 均支持完整登录条目 CRUD 与 TOTP。
|
||
|
||
AI 获取的秘密值写入密码库;普通记忆只保存密码库条目名称与用途,后续客户端可直接定位和复用。
|
||
|
||
## 文件仓储
|
||
|
||
文件正文位于数据目录,SQLite 保存可重建目录元数据。目录是一等对象,Web 与 MCP 均可创建、浏览、移动和删除空目录。
|
||
|
||
- 上传:`file_upload_prepare` 返回一次性 HTTP PUT 地址,客户端直接传输字节。
|
||
- 下载:`file_get` 返回短期签名地址,支持 HTTP Range。
|
||
- 扫描:启动时、周期或手动扫描外部新增、修改和缺失文件。
|
||
- 覆盖和删除:由明确的 Web 或 MCP 操作触发。
|
||
|
||
## 数据目录
|
||
|
||
`MEMRELAY_DATA_PATH` 下保存:
|
||
|
||
- `memrelay/`:SQLite、部署主密钥、文件正文与 Bitwarden CLI 状态。
|
||
- `basic-memory/`:Markdown、索引数据库和本地语义模型缓存。
|
||
|
||
部署主密钥与 SQLite 必须一起备份,否则已加密的 MCP Token 和密码库连接配置无法恢复。
|
||
|
||
## 备份与恢复
|
||
|
||
备份脚本会短暂停止 Compose,归档整个数据目录并生成版本清单和 SHA-256:
|
||
|
||
```powershell
|
||
.\scripts\backup.ps1
|
||
```
|
||
|
||
```bash
|
||
sh scripts/backup.sh
|
||
```
|
||
|
||
恢复:
|
||
|
||
```powershell
|
||
.\scripts\restore.ps1 -Archive .\backups\memrelay-<timestamp>.tar.gz
|
||
```
|
||
|
||
```bash
|
||
sh scripts/restore.sh ./backups/memrelay-<timestamp>.tar.gz
|
||
```
|
||
|
||
恢复脚本会先校验同目录下的 `.sha256`,支持恢复到已有实例或全新数据目录,并使用 `docker compose up -d` 创建或重启服务。目标目录非空时必须显式使用 PowerShell 的 `-Force` 或 Shell 的 `--force`。
|
||
|
||
外部 Vaultwarden/Bitwarden 数据由密码库自身备份。
|
||
|
||
## 开发与测试
|
||
|
||
后端:
|
||
|
||
```bash
|
||
cd backend
|
||
uv sync --frozen
|
||
uv run ruff check .
|
||
uv run pytest
|
||
```
|
||
|
||
前端:
|
||
|
||
```bash
|
||
cd frontend
|
||
pnpm install --frozen-lockfile
|
||
pnpm test
|
||
pnpm lint
|
||
pnpm format
|
||
pnpm build
|
||
pnpm test:e2e
|
||
```
|
||
|
||
验收覆盖真实 Basic Memory、离线本地语义模型、Vaultwarden/Bitwarden CLI、20 路 Web/MCP 混合并发、一次性上传、Range 下载、项目导出、完整 MCP 工作流、停机备份与冷恢复、Windows Docker Desktop AMD64 和物理 Linux/Armbian ARM64。
|
||
|
||
## 许可证
|
||
|
||
MemRelay 使用 [GNU AGPL v3](LICENSE)(`AGPL-3.0-only`)。第三方组件和本地模型许可见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|