开源编程智能体内存方案发布,通过 SSH 同步
用于编程代理的开源内存,通过SSH同步
一个面向编程 AI 智能体的开源内存项目在 GitHub 发布,支持通过 SSH 同步记忆数据。该项目允许智能体跨会话保留上下文,无需依赖特定云服务,用户可自托管。代码已开源,便于开发者集成与定制。
给Claude Code、Cursor这些编程代理加了个可同步的持久内存,通过SSH就能跨机器共享上下文,做多机协作开发的可以试试。
你的智能体早已解决了这个问题。deja 能找到它。
在约 12 ms 内搜索 3.3 GB 的智能体历史记录——单个零依赖二进制文件,完全本地运行。
Claude Code、Codex、opencode、aider、Gemini CLI、Cursor、Antigravity、Grok Build 和 Qwen Code 会把每一段对话写入本地文件——数 GB 已调试过的问题和设计决策,你却无法搜索。deja 是一个零依赖二进制文件,把这些历史记录变成一层记忆:
| 功能 | 作用 |
|---|---|
| 搜索 | deja "connection pool exhausted"——在数 GB 数据上约 12 ms,可追溯:你安装它之前数月的日志 |
| 智能体回忆 | MCP recall 工具——智能体回答“我们三周前修好了这个”,而不是重新调试,跨多个 harness |
| 自动回忆 | install --auto 添加一个 SessionStart 钩子:相关记忆在你提问之前就进入上下文;Claude Code 还会在压缩之前捕获当前对话记录 |
| 脱敏 | API keys、JWT、私钥在索引时会被剥离——缓存可以安全保留 |
| 统计 | deja stats——你的智能体工作,一览无余:harness、热门项目、活动迷你图 |
deja share <id>——把某次会话的脱敏摘要交给同事,密钥已提前清除 | |
| 同步 | deja sync export/import——在机器之间迁移记忆,仅追加、幂等 |
| 记住 | deja remember "text" 或 MCP remember——保留持久性的决策与结论 |
| 追溯 | deja blame <path>——哪些会话改动过这个文件,做出了什么决定以及为什么 |
| 语义 | 可选:将 deja embed 指向本地的 Ollama/LM Studio,改写后的查询依然能命中 |
隐私
deja forget 会从重建的索引中移除匹配的会话,并记录精确的会话墓碑,这样后续的 deja index 就无法从源历史中恢复它们。墓碑存储在 ~/.config/deja/tombstones(或 $XDG_CONFIG_HOME/deja/tombstones);使用 --dry-run、--list 或 --unforget。摄取排除项在 ~/.config/deja/exclude(感知 XDG)中每行一个不区分大小写的项目模式,或在 DEJA_EXCLUDE_PROJECTS 中以逗号分隔。deja stats --redaction 按 harness 和规则报告脱敏情况,以及墓碑和语义 sidecar 的相关事实。
单个二进制文件。无需下载模型,无需运行服务,除非你同步或分享,否则任何数据都不会离开你的机器。(opencode 和 Cursor IDE 的索引会调用 sqlite3 CLI,该 CLI 在 macOS 和大多数 Linux 发行版上已预装;Cursor CLI 的转录记录不需要它。)
安装
curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
或者:
go install github.com/vshulcz/deja-vu/cmd/deja@latest # Go
npx @vshulcz/deja-vu "query" # npm, no install
brew install vshulcz/tap/deja-vu # Homebrew
将它接入你使用的智能体(会修改配置,并保留一个 .bak):
deja install --all # MCP recall for every agent it finds on this machine
deja install --auto # same, plus session-start auto-recall where supported
安装还会为它检测到的 harness 写入用户级指引:Claude Code、Codex、Gemini CLI、Qwen、Copilot 和 OpenCode 使用各自对应的指引文件(或已配置的 XDG_CONFIG_HOME)。重新运行会重写 deja 的技能或标记块,而不改动周围的用户内容。使用 deja install --all --no-guidance 可选择退出;Cursor 和 Grok 没有文档记载的用户级指引位置,会被跳过。
安装会报告是否找到了本地历史,并在历史存在时立即构建首个索引。
就是这样。下一次会话时,问你的智能体:
我们之前处理过 jwt refresh rotation 吗?查一下你的记忆
——或者用 --auto,不用问:智能体在每次会话开始时就已经知道你在那个项目里解决了什么。
CLI
$ deja "jwt refresh token"
[claude] api · Jul 8 · 8f31c0a9 — 2 matches
login started failing after refresh token rotation; jwt kid mismatch in tests
fixed by reloading jwks cache after rotateKey and adding a clock-skew test
[codex] web · Jul 1 · b77d91e2 — 1 match
refresh token cookie needed SameSite=Lax in local callback flow
| 命令 | 功能说明 |
|---|---|
deja <query> | 搜索所有历史记录。多个词 = AND,常见英文填充词会被忽略,支持子串匹配(code 能找到 opencode),双引号短语要求文本连续;零结果查询会先尝试词形变化,再尝试相近拼写。--re、--harness、--project、--since 30d、--role、--json。 |
deja ctx <query> | 最佳匹配的紧凑 markdown 摘要——可直接送入提示词。 |
deja blame <path> | 查找讨论过某个文件的会话,最新的和最具体的排在最前。支持 --json、--all 以及常用过滤器。 |
deja share <id> | 为同事生成经过脱敏的会话摘要:密钥已隐去,工具噪音已剔除。 |
deja stats | 标题计数、总计、按 harness 拆分、热门项目、月度迷你走势图。--json 也一样。 |
deja doctor [--json] | 自诊断:存储解析状态、sqlite3 是否存在、每个智能体的 MCP 接线、索引健康状况、版本;--json 会为脚本输出相同的检查项。 |
deja sync export <dir> [--full] / import <dir> / ssh <host> [--pull] | 在机器之间迁移记忆——通过共享文件夹或一条 ssh 命令。带水印、仅追加、幂等。 |
deja show <id> / deja last [n] | 读取单个会话 / 列出最近的会话。 |
deja resume <id> [--exec] | 在其原生 harness 中重新打开找到的会话(claude --resume、codex resume、opencode -s、grok --resume)。 |
deja sources | 发现的存储、大小、消息数和脱敏计数。 |
deja mcp | stdio MCP 服务器(即 deja install 所接入的)。 |
deja remember "text" [--project name] | 在 notes 源中存储一条明确的事实。 |
deja warmup | 构建/刷新索引而不进行搜索——在 cron 或 shell 启动时很方便。 |
deja index [--rebuild] | 与 warmup 相同;--rebuild 会强制进行完整重建。冷构建会逐个 harness 地播报进度。 |
deja update | 下载最新的 GitHub release,校验其 checksum,并替换当前二进制文件。 |
deja statusline | 为你的状态栏提供一行信息:今天为智能体提供的 recalls 次数。deja install statusline 会将其接入 Claude Code(不会改动已有的 statusline)。 |
词干化 JSON 搜索会设置 "stemmed": true,并包含所使用的 catalog 变体。
搜索命中会带有 exact、close 或 semantic 置信度层级;接近命中会包含匹配到的变体,语义命中会包含 cosine。
分享你的统计数据
运行 deja stats --card 来生成一个自包含的 deja-stats.svg,用于 README 或个人资料页。该命令会打印一段嵌入代码片段;如果你希望把它放在个人资料或仓库中,请将 SVG 提交上去。
运行 deja stats --html 来生成一个自包含、可浏览的 deja-stats.html 时间线。HTML 导出仅嵌入元数据:日期、harness、项目、消息数量,以及已脱敏的首条用户标题;它绝不包含消息正文。
deja update 用于独立安装。Homebrew 和 npm 安装则通过包管理器更新。
Doctor JSON
deja doctor --json 会为每一项检查报告明确的状态,即使发现问题也以 0 退出。存储状态为 ok、missing、empty、unreadable 或 parsed-zero;最后一种状态意味着会话文件存在,但最新的文件没有产生任何会话。
{
"stores": [{"name": "claude", "state": "ok", "paths": ["/home/me/.claude/projects"], "files": 42}],
"index": {"state": "stale", "path": "/home/me/.cache/deja/index.db"},
"mcp": [{"name": "claude-code", "state": "wired", "path": "/home/me/.claude.json"}],
"sqlite3": {"state": "ok"},
"version": {"state": "ok", "current": "1.2.3", "latest": "1.2.3"}
}
索引状态为 ok、missing 或 stale;MCP 状态为 wired、not-wired 或 config-missing。sqlite3 状态为 ok 或 missing。版本状态为 ok、update-available、ahead、dev 或 unknown。
不使用 MCP 的上下文管道:
claude "Prior context: $(deja ctx 'database migration')"
在更改文件之前,先查看其历史记录:
deja blame cmd/deja/main.go
语义召回(可选)
语义搜索是一个可选启用的层,用于对接本地 Ollama、LM Studio 或 OpenAI 兼容的嵌入向量端点。设置 DEJA_EMBED_URL,可选设置 DEJA_EMBED_MODEL,然后运行 deja embed。Ollama 默认为 nomic-embed-text;如果没有配置且可访问的运行时,普通的词法搜索和 MCP 召回将保持不变。--no-embed 或 DEJA_EMBED=off 会在单次调用中禁用重排序。如果没有嵌入向量端点,语义零结果回退机制就不存在。
向量附属文件与索引存放在一起,文件名为 .vectors.bin,而不是存放在 index.db 中。对于 1,024 维模型,Float32 向量每 1k 条消息大约占用 4 KB,外加一个小的记录键。嵌入向量在本地进行,会消耗 CPU、内存和模型服务器时间;它从不发送原始源文件,只发送经过脱敏、截断到约 2k 字符的索引文本。
跨机器同步
将两台机器指向同一个共享文件夹(Syncthing、iCloud、git 仓库——任何能移动文件的方式):
deja sync export ~/Sync/deja # machine A: appends new batches since last export
deja sync import ~/Sync/deja # machine B: picks up what it hasn't seen
或者当另一台机器只需通过 ssh 跳转即可访问时,跳过共享文件夹:
deja sync ssh mini # push new records to mini and import them there
deja sync ssh mini --pull # fetch mini's new records into this machine
ssh 模式使用你系统的 ssh/scp 以及远程机器上的 deja 二进制文件(在 PATH 中查找,回退到 ~/.local/bin/deja)。
批次就是普通的 JSONL,输出时会做脱敏处理。导入是幂等的,所以你可以把这个文件夹当作只追加的日志保留,并按需在 cron 中运行这两条命令。记录永远不会回传到其来源。--full 会无视水位标记重新导出全部内容——在旧批次已丢失后新增机器时很有用。已同步的会话会出现在搜索中的 imported:<project> 下、recall 中,以及会话启动时的自动召回里。
教会你的智能体记住
deja install --all 接入了 MCP 召回(Claude Code、Codex、opencode、Cursor、Gemini CLI、Antigravity、Grok Build、Qwen Code——aider 没有 MCP 客户端,改用管道传入 deja ctx);deja install --auto 功能相同,并在运行框架支持的情况下增加了会话启动时的自动召回(Claude Code hook、Codex hooks.json、一个 opencode 插件——Cursor、Gemini CLI、Antigravity、Grok Build 和 Qwen Code 没有可注入上下文的 hook,所以 MCP 就是它们的完整安装方式)。要让智能体自行去调用记忆,请把下面这段加入你的 CLAUDE.md / AGENTS.md:
Before debugging or re-implementing something, run `deja "<query>"` (or the
MCP recall tool) — past agent sessions across Claude Code, Codex, opencode, aider, Gemini CLI, Cursor, Antigravity, Grok Build and Qwen Code
are indexed locally. Cite what you reuse.
MCP 工具
| 工具 | 参数 | 返回 |
|---|---|---|
recall | query、harness?、limit? | 密集匹配片段,≤4KB——对上下文开销很小。 |
recall_context | query、harness? | 最佳匹配会话的 Markdown 摘要。 |
blame | path、harness?、project?、since?、limit? | 讨论过某个文件的会话,附带标题和匹配到的上下文。 |
remember | text、project? | 存储一条持久化的决策或结论,供日后召回。 |
借助 --auto,SessionStart 钩子还会自动把当前项目近期的记忆注入进来——只读、上限 2KB,且绝不会延迟或中断智能体启动。由于 SessionStart 在每次上下文压缩后也会触发,同样的记忆会在 Claude Code 压缩后立即被重新注入——而 PreCompact 钩子会提前把对话记录捕获到索引中。
安全
子智能体的对话记录默认会被跳过(它们大多与父会话重复);设置 DEJA_INCLUDE_SUBAGENTS=1 可将其纳入索引。写入中途被捕获的文件会被安全处理——残缺的尾部行会在下一轮被补上。
凭据在索引时会被脱敏:AWS 密钥、通用的 api_key=/token= 赋值、bearer token 和原始 JWT、PEM 私钥块、服务商 token(ghp_、sk-、npm_、xox.、AIza),以及 scheme://user:pass@host URL。其值会被替换为 [redacted:<kind>];周围的文本仍可被搜索。deja sources 会显示每个存储的计数。可通过 DEJA_NO_REDACT=1 选择退出(不安全)。deja share 和 deja sync export 会在输出时重新应用脱敏。
安全模型记录了数据流、脱敏限制、信任假设以及发布验证。
支持的运行框架
| 运行框架 | 存储 | 状态 |
|---|---|---|
| Claude Code | ~/.claude/projects/**/*.jsonl | ✅ |
| Codex CLI | ~/.codex/sessions/** + history.jsonl | ✅ |
| opencode | ~/.local/share/opencode/opencode.db | ✅ |
| aider | .aider.chat.history.md | ✅ |
| Gemini CLI | ~/.gemini/tmp/*/chats/** | ✅ |
| Cursor | state.vscdb + ~/.cursor/projects/**/agent-transcripts/*.jsonl | ✅ |
| Antigravity | ~/.gemini/antigravity*/brain/*/.system_generated/logs/transcript.jsonl | ✅ |
| Grok Build | ~/.grok/sessions/**/updates.jsonl | ✅ |
| Qwen Code | ~/.qwen/projects/**/chats/*.jsonl | ✅ |
通过 DEJA_CLAUDE_ROOT、DEJA_CODEX_ROOT、DEJA_OPENCODE_DB、DEJA_AIDER_ROOTS、DEJA_GEMINI_ROOT、DEJA_CURSOR_ROOT、DEJA_CURSOR_CLI_ROOT、DEJA_ANTIGRAVITY_ROOT、DEJA_GROK_ROOT、DEJA_QWEN_ROOT、DEJA_INDEX_DIR 自定义位置。每个智能体自身的重定位变量也会被遵循:CLAUDE_CONFIG_DIR、CODEX_HOME、GEMINI_CLI_HOME、CURSOR_CONFIG_DIR、GROK_HOME、AIDER_CHAT_HISTORY_FILE,以及 Linux 上 opencode 的 XDG_DATA_HOME。
DEJA_RECALL=safe 是默认值:SessionStart 召回保持在当前项目内,过滤掉弱相关或重复的结果,优先选择最近 90 天的内容,并且最多注入 2KB。DEJA_RECALL=aggressive 会跨项目搜索,并将注入上限提高到 4KB。DEJA_RECALL=off 会禁用 SessionStart 召回输出。
会话格式注册表
会话格式注册表记录了每个受支持运行框架所观察到的存储路径、记录 schema、角色映射、时间戳以及兼容性说明。合成测试夹具会持续用解析器核对这些描述。
性能
在真实语料上测得——1,250+ 个会话,跨三个运行框架约 3.3GB:
| 测量项 | 结果 |
|---|---|
| 热搜索 | ~12 ms 典型,~25 ms 最坏情况 |
| 冷索引(一次性) | ~10 s |
| 索引大小 | 约占语料的 ~2.4% |
索引是增量的:当某个会话文件增长时,只会重新读取该文件。
基准测试
运行可复现的召回基准测试:
deja bench recall
deja bench recall --json
该合成数据集目前已被词法搜索打满(recall@5 为 1.00,中位数约 ~0.7 ms),因此它充当排序变更的回归底线,而非用来炫耀的数字;如果召回率下降,CI 会失败。语料生成器和相关性标签都是经过审查的普通 Go 代码——在信任任何数字之前,先审查"相关"的含义,包括我们的数字。当本地嵌入向量端点启动后,同一条命令会报告混合列。
工作原理
~/.cache/deja 中的本地倒排索引:解析 JSONL/SQLite 存储 → 脱敏凭证 → records.bin + token 分桶 → manifest.json 跟踪每个文件的状态,因此重复运行只会摄取发生变化的内容。MCP 服务器、统计、分享和同步都读取同一个索引。详情见:docs/ARCHITECTURE.md。
隐私:索引和搜索均在本地进行。网络仅由 deja update、deja sync ssh 以及 deja doctor 版本检查使用。本地文件输入,本地缓存输出。
常见问题
会有任何东西离开我的机器吗?索引和搜索均在本地进行。deja update 从 GitHub 下载发布版本,用户主动调用的 deja sync ssh 通过系统 SSH 客户端传输经过脱敏处理的批次。目录导出和分享仅发送到你选择的目标位置。完整数据流请参阅 安全模型。
这与 cass 有何不同?cass 是会话搜索领域的"大杂烩"方案:22 个提供商、Rust、可选的语义嵌入向量、一个 TUI。deja 则押注相反的方向——一个小的 Go 二进制文件、纯词法搜索、八种 harness、零配置——外加围绕它的记忆层组件:自动召回、脱敏、分享、同步。
那与 MemPalace / Mem0 / Letta 相比呢?那些是记忆平台:嵌入向量、向量存储、捕获钩子或 API,从部署之后开始记录。deja 完全没有捕获步骤——它索引你的智能体已经写入磁盘的内容,包括你安装它之前数月的历史记录。它们可以共存。
那我的日志中已经存在的密钥怎么办?它们保留在原始 harness 文件中(那是你的智能体的数据),但它们不会进入 deja 的索引、摘要、分享或同步导出。
那 Windows 呢? 已有构建版本,CI 会在 Windows 上运行测试套件;macOS/Linux 是经过实战检验的路径。欢迎提供实地反馈:#9。
我可以排除某个项目吗? 目前还不行——已计划为 --exclude(#8)。目前你可以把 DEJA_*_ROOT 指向一份过滤后的副本。
我该如何抹掉所有内容?
deja uninstall --all
rm -rf ~/.cache/deja
贡献
make build test lint — 参见 CONTRIBUTING.md。添加一个 harness 从 parser registry 开始。当前的优先事项和非目标见 ROADMAP.md。适合新手的问题已打上标签。
来源:Hacker News 热门(buzzing.cc 中文翻译) · github.com