Memmy:VPS 上供 AI 代理共享的本地记忆中心
了解如何在 Ubuntu VPS 上从源码构建 Memmy,启动监听 18960 端口的记忆服务,让 Claude Code、Codex 和 Cursor 共享本地 SQLite 记忆。
Memmy 的功能和存储内容
Memmy 是一个运行在您自己的 VPS(虚拟专用服务器)上的 AI 代理本地记忆中心。它使用一个 SQLite 数据库保存代理学到的内容,服务器上的所有代理都读写同一个存储库。截至 2026 年 7 月,该项目由 MemTensor memmy-agent,采用 MIT 许可证,版本为 1.0.4。
在服务器上,您只需要关注其中一部分。Memmy 提供一个监听 http://127.0.0.1:18960 的记忆服务、一个与该服务通信的 memmy-memory 命令行界面(CLI),以及一个桌面工作台。工作台仅提供 macOS 和 Windows 版本,因此在 Linux VPS 上运行服务和 CLI 即可。这样,Claude Code、Codex 和 Cursor 就能共享记忆。
Memmy 将存储内容分为四个层级。L1 Trace 是原始交互记录,包括请求、响应和工具调用。L2 Policy 是从已证明有用的交互记录中归纳出的流程。L3 World Model 是关于项目或环境的稳定知识。Skill 是从策略中固化出的可调用流程。服务在摄取交互记录时分配层级,因此您不需要手动创建这些层级。
共享记忆中心与各工具独立记忆的区别
如今,每个代理都有自己的记忆。Claude Code 将指令文件保存在仓库中。Cursor 将规则保存在其工作区数据库中。Codex 将会话日志保存在 ~/.codex 下。每个存储都属于单个工具,因此您星期一在一个工具中教过的事实,星期二在另一个工具中仍然未知。您需要为此付出两次代价:一次是花费令牌重新解释同一个项目,另一次是代理根据您已经在其他地方纠正过的假设执行错误操作。
中心会将存储移出工具。Memmy 还会读取现有存储,因此您不必从空数据库开始。其扫描器支持6个来源:~/.claude/projects/**/*.jsonl 中的 Claude Code、~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl 中的 Codex、~/.local/share/opencode/opencode.db 中的 OpenCode、Cursor 的 state.vscdb 文件、~/.openclaw 下 OpenClaw 的 SQLite 数据库,以及 ~/.hermes 下的 Hermes。您也可以手动添加来源,指定名称和本地路径。
导入计数不会一致,这是正常现象。扫描器按来源和对话对消息进行分组,然后为每个完整轮次写入一个 L1 记忆。当轮次包含非空的用户内容,并且以非空的 assistant 消息结束时,该轮次才算完整。因此,中断的会话不会产生任何内容。扫描器通过对话检查点和稳定的轮次 ID 去重。同一次运行中的扫描数量、导入消息数量和新增记忆数量都会不同。
这部分内容与Claude Code 如何在单个会话中管理上下文相对应。上下文管理决定单个窗口中能容纳哪些内容。记忆中心决定窗口关闭后哪些内容仍会保留。
VPS 所需条件
- Node.js 22 或更高版本。Memmy 文档要求此版本,而 Ubuntu 24.04 提供 Node 18。
git和构建工具链,因为better-sqlite3是原生模块,安装期间可能需要编译。- 约 2 GB RAM。root 安装会拉取较大的工作区和前端构建工具链。
- 为
node_modules和数据库预留数 GB 可用磁盘空间。
sudo apt update
sudo apt install -y git build-essential python3 curl ca-certificates sqlite3
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --versionnode --version 应输出 v22 或更高版本。此处显示 v18 表示 NodeSource 步骤未生效,后续安装将在项目的 engine 检查阶段失败。
在 Ubuntu 24.04 上从源代码安装 Memmy
git clone https://github.com/MemTensor/memmy-agent.git
cd memmy-agent
cp .env.example .env
npm install
npm run memory:buildnpm run memory:build 会将 @memmy/memory 工作区编译到 Memory/dist。无头服务器不需要编译目录树中的其他内容。检查原生模块是否已加载:
node -e "require('better-sqlite3'); console.log('better-sqlite3 loads')"如果该行抛出错误而不是打印内容,说明原生模块与您的 Node 版本不匹配。运行 npm rebuild better-sqlite3。这正是项目自带的启动脚本在启动任何内容之前执行的命令。
README 将 bash scripts/dev-start.sh 记录为一条命令启动方式。不要在无头 VPS 上运行它。它会在内存服务旁启动 Electron 桌面 Shell 和端口 19000 上的 Vite 开发服务器。Electron 需要图形显示,因此在没有图形会话的服务器上,该脚本会停滞或退出。
启动记忆服务并检查其响应
npm run memory:serve:dev这是从源代码运行记忆服务的文档方式。它绑定到 127.0.0.1:18960,将数据库保存在 ~/.memmy/memory-service/memory.sqlite,并从 ~/.memmy/config.yaml 读取配置。需要显式指定这些值时,README 中给出了相同的配置:
npm run memory:serve:dev -- \
--host 127.0.0.1 --port 18960 \
--db ~/.memmy/memory-service/memory.sqlite \
--config ~/.memmy/config.yaml在第二个 shell 中,询问服务是否正常运行:
curl -sS http://127.0.0.1:18960/api/v1/health健康检查是唯一不要求令牌的端点,因此适合作为探测请求。如果 curl 以代码 7 退出,并显示 Failed to connect to 127.0.0.1 port 18960 消息,则表示没有进程监听该端口。请查看运行服务的终端,因为启动时发生崩溃会在那里输出。最常见的原因是原生 SQLite 模块加载失败。服务启动后,ss -lntp | grep 18960 可确认套接字已建立。
其余 HTTP API(应用程序编程接口)位于 /api/v1 下。
POST /api/v1/memory/add写入记忆,POST /api/v1/memory/search执行查询。GET /api/v1/memory/:id和DELETE /api/v1/memory/:id读取并删除单条记录。POST /api/v1/sessions/open和POST /api/v1/sessions/:sessionId/close标记代理会话的开始和结束。POST /api/v1/turns/start和POST /api/v1/turns/:turnId/complete记录一轮交互。GET /api/v1/panel/overview、/api/v1/panel/analysis和/api/v1/panel/items为仪表板提供数据。
Memmy 会预留一组端口。无头模式下只使用其中的第一个:18960 用于记忆服务,18970 用于网关健康检查,18980 用于 Web UI 和管理 HTTP,18990 用于由 memmy serve 启动的 OpenAI 兼容 API,19000 和 19010 用于桌面前端的开发服务器。如果计算机上已有其他程序占用其中某个端口,请从这份列表开始排查。
memmy-memory 命令的实际来源
首次安装通常会在这里出错,因此请直接从软件包中读取信息,不要猜测。命令名称与仓库名称无关。它来自定义该命令的工作区中的 bin 字段:
node -p "JSON.stringify(require('./Memory/package.json').bin)"该命令会输出 {"memmy-memory":"./dist/src/cli/index.js"}。因此,构建后的入口点是 Memory/dist/src/cli/index.js。它只有在执行 npm run memory:build 后才会存在,因为构建过程会创建 dist 并将该文件标记为可执行。直接运行它:
node Memory/dist/src/cli/index.js health如果希望在 PATH 中使用短名称,请链接同一个文件:
sudo ln -s "$PWD/Memory/dist/src/cli/index.js" /usr/local/bin/memmy-memory
memmy-memory healthCLI 默认使用 http://127.0.0.1:18960,并接受 --url、--token、--config、--source 和 --user-id。其子命令包括 init、health、search、add、get 和 delete,此外还有供代理使用而非供用户使用的会话和轮次调用。memmy-memory search "deploy steps" 和 memmy-memory add "staging migrates on deploy" 是代理最常运行的两个命令。
如何将 Claude Code 连接到 Memmy?
Claude Code 没有记忆插件接口,因此 Memmy 不会接入其中。集成方式更简单。Claude Code 将 memmy-memory 作为普通 shell 命令运行,指令文件会告诉它何时运行。Memmy 的文档化安装程序会为您写入该文件:memmy-memory init --agent 会将记忆指令文件放入目标代理的规则目录。
建议手动编写一次该指令。这样您可以确切知道代理收到了什么指示。Claude Code 会在每次会话开始时从项目根目录读取 CLAUDE.md,因此下面这样的配置段就是完整的集成方式:
## Memory
Before starting a task, run `memmy-memory search "<topic>"` and read what comes back.
When a task is done, run `memmy-memory add "<what you learned>"` for anything that will matter next session.请明确这种方式的作用范围。它属于指令级集成,因此只有在模型决定运行该命令时才会生效。没有任何机制强制调用。如果会话结束时没有执行 add,就不会保存任何内容;下次搜索时,唯一的信号是结果为空。这与Claude Code 自带的记忆文件具有相同的取舍,但有一个区别:存储是共享的,因此同一台计算机上的 Codex 和 Cursor 也可以获取该笔记。
反向集成完全不需要配置。Memmy 的扫描器已经会读取 ~/.claude/projects/**/*.jsonl,Claude Code 会将会话记录写入该位置。在运行tmux 会话中的 Claude Code的同一台服务器上运行 Memmy,昨天的工作就会自动成为记忆,无需进行任何配置。
Memmy 能否作为 Claude Code 的 MCP 服务器运行?
不能。了解这一点可以避免浪费一下午。MCP(模型上下文协议)由客户端和服务器组成。Memmy 是客户端。它连接到 MCP 服务器,并将这些服务器提供的工具提供给自身的代理运行时。它不会发布可供 claude mcp add 连接的 MCP 端点。代码库中唯一的 MCP 桥接属于桌面本地 API 中的 Composio 集成。该 API 在 127.0.0.1 上绑定随机端口,并通过自身的 x-memmy-mcp-token 标头进行保护。
客户端配置位于 ~/.memmy/config.yaml 中。MEMMY_CONFIG 指向该文件,配置项位于 tools.mcpServers 下:
tools:
mcpServers:
example:
type: stdio
command: npx
args:
- "-y"
- "your-mcp-server"
toolTimeout: 30
enabledTools:
- "*"type 接受 stdio、sse 和 streamableHttp。stdio 服务器作为 Memmy 的子进程运行。因此,其命令必须存在于同一台主机上,并以同一用户身份运行。如果您已经在 VPS 上运行 MCP 服务器,请在此处列出这些服务器。
保持内存存储私有
Memmy 管理的所有内容都位于 ~/.memmy 下,包括 config.yaml、工作区、memory-service/memory.sqlite 和运行时文件。扫描和摄取都在本地进行,记忆会写入本地 SQLite 文件,因此默认情况下确实是本地运行。
有两条路径会访问网络。MEMMY_CLOUD_SERVICE 默认值为 https://memmy-api.memtensor.cn,账户模式会使用其试用令牌,因此 API key 模式不会调用它。记忆改进计划是隐私设置中的独立开关,默认关闭,只有手动启用后才会运行。
第三条路径更容易被忽略。如果配置了托管 embedding provider,每条记忆的文本都会发送给该 provider,以便将其转换为向量。本地存储无法避免这一步。自行托管 embedding endpoint 是阻断该网络路径的唯一方法。
将端口 18960 保持绑定到 loopback 地址。无需配置防火墙规则,因为绑定到 127.0.0.1 的服务完全无法从本机外部访问。改用 SSH 从笔记本电脑访问:
ssh -N -L 18960:127.0.0.1:18960 you@your-vps如果确实需要绑定到更宽的地址范围,请先设置令牌。在配置中设置 storage.token,或设置 MEMMY_MEMORY_TOKEN 或 MEMORY_SERVICE_TOKEN 环境变量后,除 health 之外的所有 endpoint 都需要 bearer token。配置值支持 ${ENV_NAME} 引用,因此令牌和模型 API key 不必直接写入文件。这与其他地方将机密信息排除在 AI agent 之外的做法相同;如果未来版本更改默认绑定地址,默认拒绝的 ufw 策略可以作为最后一道防线。
在信任 ~/.memmy 之前先备份
memory.sqlite 是整个存储库。向量通过 sqlite-vec 扩展存储在同一个文件中,因此备份一个文件即可。在服务写入期间使用 cp 复制文件,可能会生成损坏的数据库。请使用 SQLite 自带的备份命令:
mkdir -p ~/memmy-backup
sqlite3 ~/.memmy/memory-service/memory.sqlite ".backup '$HOME/memmy-backup/memory.sqlite'"该命令会在服务继续运行时生成一致的副本。按计划将副本传输到本机之外,这正是 restic 传输到异地存储 的用途。丢失 config.yaml,只会丢失可以重新输入的提供商设置。丢失 memory.sqlite,则会丢失所有记忆;机器上的其他位置没有第二份副本。
在 systemd 下运行内存服务
在 shell 中运行 npm run memory:serve:dev 会随 shell 一起退出。单元文件可以让服务在重启后继续运行。
[Unit]
Description=Memmy memory service
After=network-online.target
[Service]
Type=simple
User=memmy
WorkingDirectory=/opt/memmy/memmy-agent
EnvironmentFile=/etc/memmy/memory.env
ExecStart=/usr/bin/npm run memory:serve:dev
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target不要将令牌写入单元文件。将其放入 /etc/memmy/memory.env,所有者设为 root,权限设为 600:
MEMMY_CONFIG=/home/memmy/.memmy/config.yaml
MEMMY_MEMORY_TOKEN=replace-this-with-a-long-random-stringsudo systemctl daemon-reload
sudo systemctl enable --now memmy-memory
systemctl status memmy-memory --no-pager
curl -sS http://127.0.0.1:18960/api/v1/health状态输出中的 status=203/EXEC 表示 systemd 根本无法运行 ExecStart,因此请检查 which npm:在 NodeSource 安装中,它位于 /usr/bin/npm;在 nvm 中,它位于用户主目录下的某个路径,而 systemd 无法找到该路径。单元启动后立即退出,则表示 npm 内部失败;journalctl -u memmy-memory -n 50 会输出原因。其工作机制与 VPS 上的其他 systemd 服务 相同。
Memmy 目前尚不支持的功能
- 目前没有 Linux 桌面版本。打包脚本支持 macOS 和 Windows,因此工作台、引导向导和记忆面板无法在服务器本机上使用。
memory:serve:dev通过tsx运行 TypeScript 入口点,这是一条开发路径。代码仓库还提供用于编译输出的memory:serve。不带参数运行npm run,即可查看当前检出版本实际包含哪些脚本。- 检索会根据最新的 2,000 条向量记录构建搜索窗口,然后在该窗口内执行 Top-K 选择。在非常大的存储中,较早的记忆可能位于窗口之外。
- 嵌入在捕获完成后执行。失败时会进入重试队列,不会阻塞代理回合。刚添加的记忆可能尚未能通过向量搜索找到。
- 一个 SQLite 文件对应一个节点。系统不支持集群,因此第二台服务器拥有另一份独立的记忆。
截至 2026 年 7 月,版本 1.0.4 和大约 329 个 star 表明这是一个较新的项目。不同版本之间的标志、路径和脚本名称可能会变化。请读取您自己的代码检出中的 bin 字段以及 npm run 的输出,不要盲目使用从任何地方(包括本文)复制的命令。
FAQ
为什么健康检查返回 connection refused?
18960 端口上没有任何服务在监听。curl 退出码 7 和 Failed to connect to 127.0.0.1 port 18960 表示记忆服务未运行,或在启动时退出。因此,请查看启动服务的终端输出或 journal。最常见的两个原因是:better-sqlite3 原生模块与您的 Node 版本不匹配,可使用 npm rebuild better-sqlite3 修复;以及 Node 版本低于 22。服务启动后,使用 ss -lntp | grep 18960 确认套接字。
从源代码构建后,memmy-memory 命令从何而来?
它来自 @memmy/memory 工作区软件包的 bin 字段,而不是仓库名称。在检出目录中运行 node -p "JSON.stringify(require('./Memory/package.json').bin)",即可看到 {"memmy-memory":"./dist/src/cli/index.js"}。只有执行 npm run memory:build 后,该文件才会存在,因为构建过程会创建 dist 并将该文件标记为可执行。将其作为 node Memory/dist/src/cli/index.js health 运行,或将其符号链接到 /usr/local/bin,以使用简短名称。
可以使用 claude mcp add 将 Memmy 添加到 Claude Code 吗?
不可以。Memmy 是 MCP 客户端,不是 MCP 服务器。它会连接到 ~/.memmy/config.yaml 中 tools.mcpServers 下列出的服务器,并向自身运行时提供这些服务器的工具。Claude Code 通过另一种方式访问 Memmy:将 memmy-memory CLI 作为 shell 命令运行,并由 memmy-memory init --agent 写入代理规则目录的指令文件提供配置。
运行 Memmy 会将我的记忆发送到云服务吗?
扫描和导入都在本地运行,记忆会写入您自己磁盘上的 ~/.memmy/memory-service/memory.sqlite。MEMMY_CLOUD_SERVICE 会在账户模式和试用令牌下指向 https://memmy-api.memtensor.cn,记忆改进计划在您启用前保持关闭。需要监控的是嵌入提供商:托管式嵌入模型会接收每条记忆的文本,并将其转换为向量。因此,如果这点很重要,请使用您自行运行的端点。