curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
deja install --auto
$ deja "jwt refresh token" # lexical + structural search across all 43 agent stores
$ deja handoff --to codex # continue the active session's goal & state in another agent
$ deja restore internal/auth/jwt.go # recover code an agent overwrote before git commit
$ deja blame internal/auth/jwt.go:42 # trace which agent session wrote or replaced a line
deja with no arguments opens a terminal search across every agent's history — starting with
the sessions behind your uncommitted changes, then recent work in the current project.
- Navigate:
↑↓picks a session,↵opens at the match,/searches inside a session,][jump between turns,^stoggles date/relevance sort (deja search --sort date). - Filter: by agent (
codex:), time (today,yesterday,week,month), or project (in:<project>). - Resume or hand off:
rreopens the session in its native agent;ocontinues it in another agent with its goal, decisions and open work. - Recover deleted chats:
tabswitches between this project, all projects, and Deleted (sessions an agent purged that deja still holds);Rrestores one,Ddeletes (deja delete <id>),?lists all keys.
Prefer a browser? deja view exports the store — sessions, the recall audit trail, and promoted notes — into one local HTML file (try the live demo). With DEJA_TUI=0 (or deja brief), deja prints a plain-text summary.
Highlights
- Starts full on day one. Months of existing transcripts across all forty-three agents are searchable immediately — fix a bug in Codex and Claude Code, Cursor or OpenCode recalls it.
- Survives
/compactand context resets. Over 43 measured compactions, summaries kept 77% of decisions and 0.2% of commands; deja hands back the exact commands, errors, and decisions (how). - Cross-agent handoff (
deja handoff). Hit a rate limit or get stuck in Claude Code? Hand the active session's goal, decisions, touched files, and open work straight into Codex, Cursor, or OpenCode. - Undo overwritten code (
deja restore&deja blame). Indexes opened files, commands with exit codes, and exactEditspans sodeja restore <path>recovers code an agent clobbered even beforegit commit(deja blame <file>:<line>). - Automatic recall via hooks & MCP. Surfaces prior sessions at session start, before a file edit or command runs, and when a command fails.
- Tracks decision lifecycle & staleness.
deja promote <id> --state rejectedmarks a reverted approach so later hits warn why it was dropped (--state acceptedtakes the mark back), and hits report when files touched by a session have changed since. - Travels with the repository.
deja repo addcommits the decisions and dead ends you pick into.deja/memory.jsonl; a teammate's agent recalls them after a clone (repo memory). - Incremental local index. Append-only
records.binplus token buckets in~/.cache/deja, with per-file watermarks inmanifest.gobso repeat passes only read changed files (~50 ms freshness check; 4% index footprint on a 5.7 GB / 358k-message corpus). Zero LLM calls, no cloud account, and automatic credential redaction at index time (architecture, privacy).
Your own work, wrapped
deja stats --card draws your yearly agent activity in the terminal or writes an SVG for your GitHub profile (convert to PNG in browser).
Install
install.sh places the deja binary in ~/.local/bin, and deja install --auto wires MCP recall and hooks into every detected agent and builds the initial index (~10s).
Open a new session in any wired agent and it already knows what you solved in that repository — or ask it directly (have we dealt with jwt refresh rotation before?).
brew install deja-vu, nix run github:numtide/llm-agents.nix#deja-vu, go install github.com/vshulcz/deja-vu/cmd/deja@latest,
or npx @vshulcz/deja-vu "query" to try it without installing anything. Desktop apps that
take MCP servers as bundles can open the .mcpb from the
latest release; it carries the binary.
Codex CLI, opencode, Claude Code, Qwen and OpenClaw can also install the plugin
bundle directly from their own marketplaces or registries (see
Harnesses with a package of their own,
plus cursor-plugin/ for Cursor and antigravity-plugin/ for Antigravity). Copilot CLI installs the
marketplace bundle too, though it takes only the skill there — use
deja install copilot-auto for hooks and MCP:
codex plugin marketplace add https://github.com/vshulcz/deja-vu && codex plugin add deja-vu@deja-vu
opencode plugin add opencode-deja
claude plugin marketplace add vshulcz/deja-vu && claude plugin install deja-vu@deja-vu
On Windows the install script exits with unsupported OS — it is a shell script. Use
Scoop, from the main bucket every Scoop install already has, or winget, which ships with Windows:
scoop install deja-vu
winget install vshulcz.deja-vu
Or take deja-vu_<version>_windows_amd64.zip from the
latest release and put deja.exe on
your PATH, e.g. in %USERPROFILE%\.local\bin.
The binary alone is a complete install for searching: index, search, show, ctx, blame,
--json and redaction need nothing else. deja install is what wires MCP into your agents
and turns on session-start recall — worth having, and optional. On a binary-only setup
deja doctor reports every MCP target as config missing, or not-wired where the agent
is installed, which is that setup working as intended. deja warmup also leaves a skill at ~/.agents/skills/deja-search/SKILL.md
that teaches an agent the CLI contract — deja recall, ctx, blame, how to read the
recall page and ask for the next one — so it knows history is searchable without MCP. The copy in the repo is
skills/deja-search/SKILL.md.
deja install --all is --auto without the session-start recall: agents answer from memory
when they decide to call it, rather than starting each session with it. The
agent setup guide covers what each
harness supports, aider's read-only context file, and the Windows cmd /c deja mcp wrapper.
Install also writes user-level guidance for the harnesses it detects: Claude Code, Codex, opencode, Gemini CLI, Antigravity, Qwen, Kimi Code, pi, Senpi, Copilot, VS Code Copilot Chat, Goose, OpenClaw, Hermes, Roo Code, omp, Amp, prime-agent, DeepSeek Harness, Continue, Crush, CodeBuddy Code, WorkBuddy, Zed, TRAE CLI, TRAE IDE, Muse Code, CodeWhale, ZCode and Junie each get it in their own guidance file (or under the configured XDG_CONFIG_HOME). Re-run rewrites deja's skill or marked block without changing surrounding user content. Use deja install --all --no-guidance to opt out; Grok Build and Devin CLI get the shared skill in ~/.agents/skills, which is what they read; the ~/.grok/GROK.md written beside it is for the unrelated community CLI that shares that directory. Cursor has no user-level instructions file, so it gets the shared skill in ~/.agents/skills — one of the four places Cursor reads skills from — read only when something looks relevant rather than every session. Kilo Code, gajae-code, Kimchi, Command Code, Cherry Studio and Reasonix get the skill, MiniMax Code gets it inside the plugin package, and Kiro the skill and a steering file, from their own install target.
Memory in the repository
Sync moves history between your own machines. To hand the people you work with the few things your agents learned the hard way, put them in the repository:
$ deja repo candidates
4cd7e7bb9c rejected Reverted the retry with jitter: it broke idempotency because the sender re-signs each attempt with a new delivery id. (session s1, claude 2026-08-03)
$ deja repo add 4cd7e7bb9c
added 1 entry to .deja/memory.jsonl
nothing is committed: review with `git diff .deja/` and commit it like code
Candidates come from this project's history in every agent: promoted and remembered
notes, reversals reported in a session, and what sessions settled. Nothing is written
until you pick, every entry is redacted on the way in, and one that still matches a secret
rule is refused. The file is JSON lines sorted by a content hash, with a
merge=union attribute beside it, so parallel additions merge; deleting a line removes
an entry. After a clone, the entries come back at session start and in recall, in any agent
deja is wired into, marked as from the repository and framed as untrusted like the rest.
{"activations":{"auto":{"repo":false}}} in the trust policy keeps them out of the hooks.
More.
Privacy
Indexing and search are local. The network is used only by deja update, deja sync ssh,
the version check in deja doctor, deja embed against an endpoint you configure (and,
once it has built the semantic sidecar, each search, which sends the query to that
endpoint), and a once-a-day look at the latest release from an interactive command. That look sends no
session data; DEJA_OFFLINE=1 turns it off, and so does DEJA_NO_UPDATE_NOTICE set to any
value, which also hides the note a new version prints on its first run.
Credentials are stripped as the index is built: cloud and provider keys, tokens and JWTs,
PEM blocks, passwords in URLs or stated in prose. Each becomes [redacted:<kind>] and the
text around it stays searchable. The source transcripts still hold them
(one machine had 84 in 42 sessions):
deja secrets names those sessions without printing a value, and deja secrets --scrub
rewrites the ones it can, keeping the original beside the file.
deja forget drops sessions and keeps them dropped across rebuilds. ~/.config/deja/exclude
skips a project per line, or a whole store with harness:opencode. The
security model has the data flows and what redaction cannot catch.
CLI
Bare deja in a terminal opens the search screen. With a query,
or any command below, it prints and exits:
$ 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
Ask your history
When the first word of a bare query has at least four characters and is one
edit from a command name, deja names that command on stderr and then searches
as usual. deja search <query> skips the suggestion.
Use what it finds
Move it and check it
Full reference: commands and JSON output.
MCP tools
The server exposes one tool, deja, with a mode; deja install wires it in. One tool
costs 477 tokens of definitions a turn, against 8,283 for the largest of the seven servers
measured in day zero. The six
older tool names (recall, recall_context, blame, fix, how, remember) still answer.
deja mcp --context-search is a separate server with a single context_search tool, for
Qwen Code's External Context MCP Profile v1 (Qwen page).
q carries whatever the mode asks about. The per-mode names below are still
accepted; they are no longer declared, because the schema is read every turn
whether or not the tool is called.
Supported harnesses
aider · Amp · Antigravity · Claude Code · Cline · Codex CLI · Copilot CLI · VS Code Copilot Chat · Cursor · DeepSeek Harness · Gemini CLI · Goose · Grok Build · Hermes · Kimi Code · omp (Oh My Pi) · OpenClaw · opencode · Continue · Crush · pi · prime-agent (PrimeIntellect) · Qwen Code · Cherry Studio · Senpi · gajae-code · Kimchi Coding · Command Code · ZCode · Kiro · Kilo Code · Roo Code · Zed · Devin CLI · CodeWhale · Junie · JetBrains AI Assistant · Windsurf / Devin Desktop · CodeBuddy Code · Reasonix · TRAE CLI · Muse Code · MiniMax Code.
✅ works · — possible, not built yet · ✕ the harness has no such mechanism · ⚠ waiting on the harness itself · ? not investigated
TRAE IDE is wired, not read: its chats are in an encrypted database. deja install trae-ide
adds the MCP server and the skill, and trae-ide-auto adds hooks, which TRAE IDE runs only
after you turn them on in Settings > Hooks.
Custom store locations go through DEJA_*_ROOT variables, and each agent's own relocation
variable is honored too. The
session format registry documents
the observed paths, record schemas and role mapping per harness, with synthetic fixtures
keeping those descriptions checked against the parsers.
Harnesses with a package of their own
deja install --auto wires every one of these like every other harness, and
that stays the shortest path. They also have a package in their own ecosystem,
for people who install extensions there rather than from a CLI:
Either path works alone, and both together double nothing: each package reads what
deja install already wrote and uses the deja you already have.
In a Spec Kit project, an extension adds
/speckit.deja-vu.recall, which searches past sessions for the feature before you
implement it:
specify extension add deja-vu --from https://github.com/vshulcz/deja-vu/releases/latest/download/deja-spec-kit.zip
The same search is also a skill, for any agent that loads a SKILL.md:
npx skills add https://github.com/vshulcz/deja-vu --skill deja-search # skills CLI: Claude Code, Cursor, Goose, Copilot…
openclaw skills install @vshulcz/deja-search # ClawHub
hermes skills install vshulcz/deja-vu/skills/deja-search # Hermes
The skill drives the deja binary from the install step above; it does not bundle one.
Semantic recall (optional)
Point deja embed at a local Ollama, LM Studio or OpenAI-compatible endpoint with
DEJA_EMBED_URL and rephrased queries still hit. Without a reachable runtime, lexical
search and MCP recall continue unchanged. OpenAI Platform works with its standard key:
export OPENAI_API_KEY='sk-...'
export DEJA_EMBED_URL='https://api.openai.com/v1/embeddings'
export DEJA_EMBED_MODEL='text-embedding-3-small'
deja embed
With no DEJA_EMBED_URL set, deja probes localhost:11434 and localhost:1234,
so a machine already running Ollama or LM Studio is picked up without being asked.
DEJA_EMBED_OFF=1, or DEJA_EMBED_URL=off, turns that probe off — any other
configured DEJA_EMBED_URL still wins.
For another authenticated OpenAI-compatible endpoint, set DEJA_EMBED_KEY explicitly:
export DEJA_EMBED_URL='https://example.com/v1/embeddings'
export DEJA_EMBED_MODEL='embedding-model'
export DEJA_EMBED_KEY='...'
deja embed
DEJA_EMBED_KEY takes precedence. OPENAI_API_KEY is used automatically only for an
HTTPS api.openai.com URL; it is never implicitly sent to local or third-party endpoints.
Models trained with instruction prefixes, such as the multilingual E5 family, need them on
both sides. DEJA_EMBED_QUERY_PREFIX goes in front of every search query and
DEJA_EMBED_PASSAGE_PREFIX in front of every indexed text; both are empty by default:
export DEJA_EMBED_MODEL='multilingual-e5-small'
export DEJA_EMBED_QUERY_PREFIX='query: '
export DEJA_EMBED_PASSAGE_PREFIX='passage: '
deja embed
The passage prefix is part of the sidecar's model name, so changing it embeds everything again, and search ignores vectors made with another model or prefix (it says so once).
The sidecar sits beside the index as .vectors.bin, not inside index.db. Float32 vectors
cost roughly 4 MB per 1k messages for a 1,024 dimension model. A remote endpoint receives
the redacted indexed text, truncated to about 2k characters, but never raw source files.
With Ollama or LM Studio, embedding stays local and needs no key.
Proof
Millisecond lookups, and on LongMemEval-S 88.9% hit@1 (470-question cleaned set) and 88.2% hit@1 on all 500 questions; on LoCoMo retrieval, 71.9% hit@1. On a task this machine had already solved, 58% fewer tokens: eleven runs an arm, 53,558 against 126,222 with nothing wired, and 52,815 against 103,443 on a later build with the arms alternated. Both retrieval harnesses ship in this repo and run on the public datasets in minutes: benchmarks · what one task costs.
The rest is measured by deja bench:
deja bench recall # ranking floor: 100 queries, half Russian, CI fails if recall drops
deja bench context # 30 seeded task chains plus five negative controls
deja bench block # does the answer survive into what deja hands over
deja bench prompt # what the per-prompt hook fires on, and what it fires on wrongly
deja bench ingest # what an update costs: unchanged, a turn, a new transcript, a rename, a rewrite
deja bench read # what it costs to read a database-backed store, and what one long value does to it
bench block asks the question the others cannot: with the right session in
hand, does the block carry what that session settled. Eight sessions discuss each
subject and one of them settles it, in the middle of its own transcript rather
than at the end — so the baseline arm, the newest turns of the top hit, scores
zero and an arm above zero had to choose.
The context experiment compares deja-recall against full-history, naive grep and cold context. With the default seed:
Same fact coverage as grepping the raw logs for about 250x fewer tokens, and about 70x fewer than replaying the matched sessions in full, while injecting nothing on the chains where no prior fact is relevant. The corpus generator and the relevance labels are ordinary reviewed Go. Audit what "relevant" means before trusting any figure, ours included.
Measured on a real store of 2,419 sessions and 179k messages, 1.9 GB of transcripts:
The same store has since grown to 2,754 sessions, 358k messages and 5.7 GB. A cold full build over it takes 71 s and writes a 232 MB index — 4% of the corpus, because the share falls as transcripts repeat themselves — and the end-to-end median is unchanged at 0.25 s. Since 0.23.2 records are compressed from 256 bytes, which takes a 19k-session index from 277 to 185 MB.
The index is incremental. When a session file grows, only that file is re-read. When one is rewritten, its new records are appended and the old ones zeroed in place. On a 40,000-session store a pass over 20 rewritten transcripts takes 1.7 s and peaks under 1 GB, and a search for a word most sessions hold takes about a second.
How it works
Local inverted index in ~/.cache/deja: parse the JSONL and SQLite stores, redact
credentials, write an append-only records.bin plus token buckets, and track per-file state in
manifest.gob so repeat runs only ingest what changed. The MCP server, stats, share and
sync all read that one index. Details in docs/ARCHITECTURE.md.
FAQ
engram is the strongest of the record-forward tools and worth your time if that model fits you; it still starts empty and knows only what an agent chose to save. The full comparison covers 15 of them.
A recall is a lexical lookup against a local index:
0.7–0.8 ms median, and nothing waits on a model. A hook adds the process start and a
freshness check over your stores on top of that: about 0.2 s end to end on a 1.9 GB
store. On an index of 19k sessions the per-prompt hook takes 107 ms at the median,
and a recall through deja mcp 85 ms.
Under ~/.claude/projects, one JSONL file per session; Codex keeps ~/.codex/sessions, Cursor a
SQLite state.vscdb. deja reads them all in place: bare deja opens a screen to search
and read them, deja search does it from a script, deja last lists the recent
sessions of every agent, and deja view opens the whole history as one local page. Paths
for each agent: where sessions are stored.
Claude Code deletes transcripts older than 30 days (cleanupPeriodDays in ~/.claude/settings.json), and claude --resume lists
only what is left. A session deja indexed before the cleanup stays searchable after the
file is gone, and the weekly note at session start says how many it kept, with an id
deja resume <id> --write-back puts back. Details: session files on disk.
Under ~/.config/deja (or $XDG_CONFIG_HOME/deja):
policy.json(DEJA_POLICY_FILEmoves it) — JSON object with four optional keys:"activations": per-surface origin rules for"search","mcp"and"auto"(hooks), keyed by"local","imported","imported:<group>"or"*"(true/false).DEJA_AUTORECALL_LOCAL_ONLY=1setsactivations.auto.importedtofalse."ignore": array of shell globs matched against session path and project to exclude from recall andsync(default["*/.claude/jobs/*"])."auto_index":falsestops automatic index updates on search, MCP recall and hooks (same asDEJA_NO_AUTO_INDEX=1)."search_only":trueskips mining fixes, commands and co-occurrence, saving ~20% of build CPU (same asDEJA_SEARCH_ONLY=1).
exclude— one project name or path pattern per line to skip at index time andsync export, orharness:<name>(e.g.harness:opencode) to skip a store (DEJA_EXCLUDE_PROJECTS,DEJA_EXCLUDE_HARNESSES).projects— one<path> = <name>per line to group multiple checkouts or worktrees as one project.rules.md— standing instructions copied into each installed agent's global rules file bydeja rules sync.- State files written by deja —
peers.json(deja sync ssh),settled.json(deja friction --settle),tombstones(deja forget),wiring.jsonandbin/deja-hook(deja install).
Hook recall mode is set by DEJA_RECALL: safe (default, 2 KB cap and up to 3 sessions from the current project at session start), aggressive (4 KB cap and up to 6 sessions across projects), or off (silences all hooks). The DEJA_INDEX_* switches and full configuration table are in the commands guide.
List the trees in ~/.config/deja/projects, one <path> = <name> per line:
~/work/monorepo = work
~/work/worktrees = work
Every directory under a listed path is then that project, for indexing, the hooks and recall alike; the longest matching path wins. Run deja index --rebuild to re-file existing transcripts under the new name. The exclude file still wins over project aliases.
deja uninstall --all
rm -rf ~/.cache/deja ~/.local/share/deja ~/.config/deja
The index is under ~/.cache/deja, your remember and promote notes in
~/.local/share/deja, and the rules, exclude list, project aliases and hook launcher in
~/.config/deja (or under XDG_DATA_HOME and XDG_CONFIG_HOME when set; on
Windows the notes are in %AppData%\deja).
Guides
- Context & recovery: Does your agent remember previous conversations? · The agent lost the context you had · The context window is full · What compaction drops · Why agents forget between sessions
- Resuming & finding: Resuming yesterday's session · Finding the session where you solved it · The agent repeats a mistake you already fixed · Switching agents
- Session files & cleanup: Session files on disk · Where each agent keeps its history · Recovering a deleted Claude Code session · Claude Code: No conversation found with session ID · Codex resume session · Deleting old Claude Code sessions
- Comparisons & operations: What each memory tool knows the day you install it · Memory plugins compared · What memory costs · Auditing an agent · Exporting a conversation · Across machines
Claude Code · Codex · Cursor · Windsurf · opencode · DeepSeek Harness · Kimi Code · Zed · Grok Build · Gemini CLI · Qwen Code · OpenClaw · Goose · Cline · pi · Hermes · Copilot CLI · Copilot Chat · aider · Amp · Antigravity · Continue · Crush · Roo Code · Kilo Code · Kiro · Cherry Studio · · · · · · · · · ·
Contributing
make build test lint, then CONTRIBUTING.md. Adding a harness starts in
the parser registry. Priorities and non-goals are in
ROADMAP.md. Good first issues are labeled.
Support
Bugs and questions go to issues. Anything you think is exploitable goes through the private advisory link in SECURITY.md instead. What deja reads, what it never sends anywhere, and how to exclude a project or forget a session is under Privacy. Found it useful? Star deja-vu on GitHub.
License
MIT © Vladislav Shulcz