{"slug": "open-source-memory-for-coding-agents-synced-over-ssh", "title": "Open-source memory for coding agents, synced over SSH", "summary": "Deja, a zero-dependency binary, turns local agent conversation histories into a searchable memory layer that works over SSH, enabling developers to retrieve past debugging sessions and design decisions without external services. The tool indexes gigabytes of logs in milliseconds, supports agent recall via MCP, and includes redaction of secrets, making it safe to share sanitized digests across machines.", "body_md": "**Your agents already solved this. deja finds it.**\n\nClaude Code, Codex and opencode write every conversation to local files — gigabytes of debugged problems and design decisions you can't search. deja is a zero-dependency binary that turns those histories into a memory layer:\n\nSearch |\n`deja \"connection pool exhausted\"` — 7–9 ms over gigabytes, retroactive: months of logs from before you installed it |\nAgent recall |\nMCP `recall` tool — the agent answers \"we fixed this three weeks ago\" instead of re-debugging, across harnesses |\nAuto-recall |\n`install --auto` adds a SessionStart hook: relevant memory lands in context before you ask |\nRedaction |\nAPI keys, JWTs, private keys are stripped at index time — the cache is safe to keep |\nStats |\n`deja stats` — your agent work, wrapped: harnesses, top projects, activity sparkline |\nShare |\n`deja share <id>` — hand a colleague a sanitized digest of a session, secrets already scrubbed |\nSync |\n`deja sync export/import` — move memory between machines, append-only, idempotent |\n\nOne binary. No models to download, no services to run, nothing leaves your machine. (opencode indexing shells out to the `sqlite3`\n\nCLI, preinstalled on macOS and most Linux distros.)\n\n```\ncurl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh\n```\n\nor:\n\n```\ngo install github.com/vshulcz/deja-vu/cmd/deja@latest   # Go\nnpx @vshulcz/deja-vu \"query\"                            # npm, no install\nbrew install vshulcz/tap/deja-vu                        # Homebrew\n```\n\nWire it into the agents you use (edits config, keeps a `.bak`\n\n):\n\n```\ndeja install --all          # MCP recall for claude-code, codex, opencode\ndeja install claude-code --auto   # + SessionStart auto-recall hook\n```\n\nThat's it. Next session, ask your agent:\n\nhave we dealt with jwt refresh rotation before? check your memory\n\n— or with `--auto`\n\n, don't ask: the agent starts each session already knowing what you solved in that project.\n\n``` bash\n$ deja \"jwt refresh token\"\n[claude] api        · Jul 8 · 8f31c0a9 — 2 matches\n  login started failing after refresh token rotation; jwt kid mismatch in tests\n  fixed by reloading jwks cache after rotateKey and adding a clock-skew test\n[codex]  web        · Jul 1 · b77d91e2 — 1 match\n  refresh token cookie needed SameSite=Lax in local callback flow\n```\n\n| Command | What it does |\n|---|---|\n`deja <query>` |\nSearch all histories. Multi-word = AND, substrings match (`code` finds `opencode` ). `--re` , `--harness` , `--project` , `--since 30d` , `--role` , `--json` . |\n`deja ctx <query>` |\nCompact markdown digest of the best match — pipe it into a prompt. |\n`deja share <id>` |\nSanitized session digest for a colleague: secrets redacted, tool noise stripped. |\n`deja stats` |\nTotals, per-harness split, top projects, monthly sparkline. `--json` too. |\n`deja sync export <dir> [--full]` / `import <dir>` / `ssh <host> [--pull]` |\nMove memory between machines — via a shared folder or one ssh command. Watermarked, append-only, idempotent. |\n`deja show <id>` / `deja last [n]` |\nRead one session / list recent ones. |\n`deja sources` |\nDiscovered stores, sizes, message and redaction counts. |\n`deja mcp` |\nThe stdio MCP server (what `deja install` wires in). |\n`deja warmup` |\nBuild/refresh the index without searching — handy in cron or shell startup. |\n\nContext piping without MCP:\n\n```\nclaude \"Prior context: $(deja ctx 'database migration')\"\n```\n\nPoint both machines at one shared folder (Syncthing, iCloud, a git repo — anything that moves files):\n\n```\ndeja sync export ~/Sync/deja   # machine A: appends new batches since last export\ndeja sync import ~/Sync/deja   # machine B: picks up what it hasn't seen\n```\n\nOr skip the shared folder when the other machine is a ssh hop away:\n\n``` python\ndeja sync ssh mini          # push new records to mini and import them there\ndeja sync ssh mini --pull   # fetch mini's new records into this machine\n```\n\n`ssh`\n\nmode uses your system ssh/scp and the `deja`\n\nbinary on the remote (looked up on PATH, falling back to `~/.local/bin/deja`\n\n).\n\nBatches are plain JSONL, redacted on the way out. Import is idempotent, so keep the folder as an append-only log and run both commands from cron if you like. Records never echo back to their origin. `--full`\n\nre-exports everything regardless of watermarks — useful when adding a machine after old batches are gone. Synced sessions show up under `imported:<project>`\n\nin search, `recall`\n\n, and session-start auto-recall.\n\n`deja install --all`\n\nwires up MCP recall and the session-start hook. To make\nthe agent reach for memory on its own, add this to your `CLAUDE.md`\n\n/\n`AGENTS.md`\n\n:\n\n```\nBefore debugging or re-implementing something, run `deja \"<query>\"` (or the\nMCP recall tool) — past agent sessions across Claude Code, Codex and opencode\nare indexed locally. Cite what you reuse.\n```\n\n| Tool | Arguments | Returns |\n|---|---|---|\n`recall` |\n`query` , `harness?` , `limit?` |\nDense matching snippets, ≤4KB — cheap on context. |\n`recall_context` |\n`query` |\nMarkdown digest of the best-matching session. |\n\nWith `--auto`\n\n, a SessionStart hook also feeds the current project's recent memory in automatically — read-only, capped at 2KB, and it never delays or breaks agent startup.\n\nCredentials are redacted at index time: AWS keys, generic `api_key=`\n\n/`token=`\n\nassignments, bearer tokens and raw JWTs, PEM private key blocks, provider tokens (`ghp_`\n\n, `sk-`\n\n, `npm_`\n\n, `xox.`\n\n, `AIza`\n\n), and `scheme://user:pass@host`\n\nURLs. The value is replaced with `[redacted:<kind>]`\n\n; surrounding text stays searchable. `deja sources`\n\nshows per-store counts. Opt out with `DEJA_NO_REDACT=1`\n\n(unsafe). `deja share`\n\nand `deja sync export`\n\nre-apply redaction on the way out.\n\n| Harness | Store | Status |\n|---|---|---|\n| Claude Code | `~/.claude/projects/**/*.jsonl` |\n✅ |\n| Codex CLI | `~/.codex/sessions/**` + `history.jsonl` |\n✅ |\n| opencode | `~/.local/share/opencode/opencode.db` |\n✅ |\n| aider, Gemini CLI |\n|\n\nCustom locations via `DEJA_CLAUDE_ROOT`\n\n, `DEJA_CODEX_ROOT`\n\n, `DEJA_OPENCODE_DB`\n\n, `DEJA_INDEX_DIR`\n\n.\n\nMeasured on a real corpus — 1,250+ sessions, ~3.3GB across three harnesses:\n\n| Warm search | 7–9 ms typical, ~40 ms worst-case |\n| Cold index (once) | ~10 s |\n| Index size | ~2.4% of corpus |\n\nThe index is incremental: when a session file grows, only that file is re-read.\n\nLocal inverted index in `~/.cache/deja`\n\n: parse JSONL/SQLite stores → redact credentials → `records.bin`\n\n+ token buckets → `manifest.json`\n\ntracks per-file state so repeat runs only ingest what changed. The MCP server, stats, share and sync all read the same index. Details: [docs/ARCHITECTURE.md](/vshulcz/deja-vu/blob/main/docs/ARCHITECTURE.md).\n\n**Privacy:** no network path exists in the indexing or search code. Local files in, local cache out.\n\n**Does anything leave my machine?** No. There is no network code in the tool. `sync`\n\nwrites files to a directory you choose; moving them is up to you.\n\n**How is this different from cass?**\n[cass](https://github.com/Dicklesworthstone/coding_agent_session_search) is the kitchen-sink take on session search: 22 providers, Rust, optional semantic embeddings, a TUI. deja is the opposite bet — one small Go binary, pure lexical, three harnesses, zero setup — plus the memory-layer pieces around it: auto-recall, redaction, share, sync.\n\n**And from MemPalace / Mem0 / Letta?**\nThose are memory *platforms*: embeddings, vector stores, capture hooks or APIs that record going forward. deja has no capture step at all — it indexes what your agents already wrote to disk, including months of history from before you installed it. They can coexist.\n\n**What about secrets already in my logs?** They stay in the original harness files (that's your agent's data), but they don't enter deja's index, digests, shares or sync exports.\n\n**What about Windows?** Builds exist, CI runs the suite on Windows; macOS/Linux are the battle-tested paths. Field reports welcome: [#9](https://github.com/vshulcz/deja-vu/issues/9).\n\n**Can I exclude a project?** Not yet — planned as `--exclude`\n\n([#8](https://github.com/vshulcz/deja-vu/issues/8)). Today you can point `DEJA_*_ROOT`\n\nat a filtered copy.\n\n**How do I wipe everything?**\n\n```\ndeja uninstall --all\nrm -rf ~/.cache/deja\n```\n\n`make build test lint`\n\n— see [CONTRIBUTING.md](/vshulcz/deja-vu/blob/main/CONTRIBUTING.md). Adding a harness is one parser file: [docs/ARCHITECTURE.md](/vshulcz/deja-vu/blob/main/docs/ARCHITECTURE.md#adding-a-harness). Good first issues are labeled.\n\nMIT © [Vladislav Shulcz](https://github.com/vshulcz)", "url": "https://wpnews.pro/news/open-source-memory-for-coding-agents-synced-over-ssh", "canonical_source": "https://github.com/vshulcz/deja-vu/", "published_at": "2026-07-15 16:15:03+00:00", "updated_at": "2026-07-15 16:28:34.980197+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["deja", "Claude Code", "Codex", "opencode", "MCP", "GitHub", "Homebrew"], "alternates": {"html": "https://wpnews.pro/news/open-source-memory-for-coding-agents-synced-over-ssh", "markdown": "https://wpnews.pro/news/open-source-memory-for-coding-agents-synced-over-ssh.md", "text": "https://wpnews.pro/news/open-source-memory-for-coding-agents-synced-over-ssh.txt", "jsonld": "https://wpnews.pro/news/open-source-memory-for-coding-agents-synced-over-ssh.jsonld"}}