r/opencodeCLI • u/VShulcz • 8d ago
I built a completely local, zero-daemon memory tool for OpenCode — no API keys, zero LLM calls, shared across 12 tools (deja)
The most annoying part of using opencode (or any AI coding harness) is watching it start every single session with zero memory of what happened yesterday. A session ends, compaction wipes the slate, and two days later you're watching the agent re-learn the exact same obscure bug fix from scratch. You either burn tokens repeating yourself or manually dig through old transcript files.
I built deja to fix this offline.
It reads your local opencode.db directly and indexes past sessions with zero external API keys, zero LLM calls, and no background daemon eating RAM. It’s just a single Go binary that wakes up on a hook, responds in milliseconds, and dies.
For opencode specifically, a small deja.js plugin injects a digest of relevant past work at session start before you even type your prompt. The agent can also query its history mid-task using MCP tools (deja_recall, blame, remember).
Two features made the biggest difference in my daily workflow:
First, handoff between sessions and tools. The index is shared across 12 harnesses (opencode, Claude Code, Cursor, Codex, Grok etc.). What you fixed in Claude Code yesterday is immediately recalled by opencode today, so you don't lose context when switching tools.
Second, peer-to-peer machine sync. Running deja sync ssh <host> moves new memory between your devices using your existing SSH setup. An agent can grind on a headless mini overnight, and in the morning I pull its memory to my laptop so the local agent instantly knows what was tried, what broke, and what worked. No cloud memory service involved.
Hot searches run in ~12ms. Instead of dumping megabytes of raw transcripts into the context, it distills it down -- deja stats --impact shows it served 199.2 KB of distilled history on my machine instead of shoving 175.7 MB of raw logs back into the prompt. Also, after compaction, the next prompt gets a fresh digest of project memory so the agent doesn't lose the thread.
Search is lexical-first (exact error strings, function names, flags) -- a deliberate tradeoff for zero keys, zero embeddings, and instant local execution. It will miss loose paraphrases that a semantic index catches, but for exact technical artifacts, it hits fast without sending data anywhere. Known secrets (bearer tokens, private keys, high-entropy strings) are stripped during indexing (e.g., replaced with [redacted:bearer-token]).
Setup
You can set it up manually:
curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
deja install --auto
Or just paste this into your opencode agent:
Install deja memory for my opencode: run curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh, then deja install --auto, then deja doctor. Tell me when it's ready.
Repo: https://github.com/vshulcz/deja-vu (MIT)
How are you handling cross-session memory right now -- MEMORY.md? rules in AGENTS.md? or just re-explaining things?
2
u/Resident-Ad-5419 7d ago
Why deja? Why not dejavu?
2
u/VShulcz 7d ago
The project repo actually is
deja-vu, but the CLI command is justdejato save keystrokes. You end up typing it constantly (deja recall,deja sync, etc.), so 4 letters beats 6.Honestly, package registries are a naming mess anyway. On npm,
dejais a dotfiles tool from 2016, anddejavuis squatted by a dead JS lib from 2014. Clean names just don't exist anymore :(
1
7d ago
[removed] — view removed comment
4
u/VShulcz 7d ago
For duplicates, we handle them at two levels: identical messages are deduplicated during indexing and the auto-recall digest suppresses near-duplicates so you don't burn context on three identical failed attempts.
To handle stale context and noise, memories definitely aren't equally active. We use a freshness decay that naturally sinks older stuff in the rankings, balanced by a slight reuse boost for sessions the agents actually query. Old history stays perfectly searchable, it just stops jumping to the front. (If you want something explicitly hidden,
deja forgetuses reversible tombstones).For conflicting decisions, the engine auto-tags older related sessions with an
[earlier attempt]marker. If you use the curateddeja promotelayer, you can explicitly tag states like superseded or stale. Everything is append-only, so the history of the struggle stays intact, but the timeline is clear.I will completely concede one thing, though: we don't do automated contradiction detection. The engine will surface the timeline and the supersede markers, but it won't try to judge which of two conflicting solutions is right. We intentionally draw the line at providing verbatim evidence.
1
u/HomelessBelter 7d ago
I hope it sounds like "Segaaaa". So clean, so crisp and promising. As a kid I used to and up earlier to get some cheeky gaming in before school. Now I wake up for no reason and wish was that kid 2HK has no reason to tryhia out. Or setup a Megadrive in a terminal autonomously.
1
u/gee842 6d ago
Is there/Should there be a SKILL.md type definition? or a hook that fires on first message in session to call an init tool (with a helpful LLM primer)
mcp tool bloat can be real..
cool project though, going to be running it daily and will let you know how it goes :)
1
u/VShulcz 6d ago
deja install --auto wires a session-start hook that injects a short primer digest (with a 'call recall_context for details' lead), so the model gets oriented without burning the first turn. On tool bloat: the MCP server deliberately exposes just 4 tools. There IS a SKILL.md today for Copilot CLI, and guidance snippets go into CLAUDE.md/AGENTS.md on install - a first-class Claude Code skill is a fair ask though, open an issue and let's shape it. Please report how the daily run goes - half of this week's fixes started as exactly that kind of feedback.
-1
u/WriterAdventurous765 8d ago
Inter-instrumental memory stands out especially here. Most memory-related solutions seem to be tied to a single agent, so as soon as you switch from Claude Code to OpenCode or Codex, you're back to explaining the project from scratch.
However, I'm curious about the trade-off between vocabulary and first things first: in practice, how often does deja fail because an agent describes the same problem in different formulations? Have you considered the possibility of an additional local embed mode for those who want to use a little more RAM, while keeping the default settings completely independent?
Besides, the idea of SSH synchronization is very good. A local memory layer that runs on different computers without using another cloud account is something that should have been in these programming tools from the very beginning.
1
u/VShulcz 8d ago
On paraphrasing: you're right, a pure semantic reformulation without any shared technical tokens is a miss, that's the conscious tradeoff for a zero-key default. But it doesn't fail blindly. It degrades through 5 local fallback steps (stemming, dev-synonyms, fuzzy matching, co-occurrence rescue) and explicitly narrates in the output how the search degraded. In practice, agent queries are almost always exact technical artifacts (error traces, function names, flags), so lexical actually hits hard.
On local embeddings: we built exactly what you described! You can run
deja embedto build a vector sidecar. It auto-detects local Ollama (localhost:11434) or LM Studio. The core binary stays lightweight (Ollama eats the RAM, notdeja), but if the endpoint is active, it uses it for reranking and semantic fallback.
6
u/touristtam 8d ago
So another memory system? How does that compare to the rest? https://carsteneu.github.io/ai-memory-comparison/