Persistent memory for OpenCode, powered by Claude-Mem.
Share the same Claude-Mem worker, database, and search tools between Claude Code and OpenCode. Once connected, previous observations and summaries are injected into new OpenCode sessions automatically.
Note: This plugin is a thin OpenCode adapter for an existing Claude-Mem installation. It does not install Claude-Mem, manage slash commands, or start the worker for you.
- Install and configure Claude-Mem in Claude Code.
- Add this plugin to your
opencode.json:
{
"plugin": ["@ephemushroom/opencode-claude-mem"]
}- Restart OpenCode.
- Start a session — memory context will be injected automatically when the Claude-Mem worker is available.
- Shared Memory — Uses the same Claude-Mem worker and memory store as Claude Code.
- Auto-Start — When the plugin loads and the Claude-Mem worker is not
already running, it spawns
bunx claude-mem startonce per OpenCode process (skipped silently ifbunis not onPATHor the worker is already up). - Automatic Context Injection — Injects relevant project memory into the system prompt for new OpenCode turns.
- Compaction Support — Re-injects memory context during OpenCode session compaction so long conversations keep their historical context.
- Observation Capture — Sends tool observations to Claude-Mem for future retrieval and summarization.
- Observation Hardening — Skips low-value meta tools, strips
<claude-mem-context>and<private>tags before storage, and truncates oversized observation payloads by UTF-8 byte size. - Graceful Degradation — If the worker is offline and cannot be started, the plugin fails open and OpenCode continues to work normally.
OpenCode session
|
|-- plugin loads
| '-- connect to Claude-Mem worker on port 37777
|
|-- session.created ................ track session + reset cache
|-- chat.message ................... init session with real user prompt
|-- tool.execute.after ............. send tool observation
|-- system.transform ............... inject memory into system prompt
|-- session.compacting ............. preserve memory during compaction
|-- message.updated ................ capture assistant text (debounced)
|-- file.edited .................... record file edit observation
|-- session.compacted .............. summarize after compaction
|-- session.idle ................... flush + summarize + complete session
'-- session.deleted ................ flush + complete (no zombie sessions)
The plugin is intentionally small. It only adapts OpenCode hook events to the Claude-Mem worker HTTP API. All indexing, summarization, memory search, and storage stay in upstream Claude-Mem.
OpenCode <-> Plugin (this repo) <-> Claude-Mem Worker (port 37777) <-> SQLite + ChromaDB
| Claude Code | OpenCode plugin | Purpose |
|---|---|---|
SessionStart |
experimental.chat.system.transform |
Inject memory context |
SessionStart |
experimental.session.compacting |
Preserve memory during compaction |
UserPromptSubmit |
chat.message |
Initialize session with real user prompt |
PostToolUse |
tool.execute.after |
Capture tool observations |
| (streaming) | event (message.updated) |
Capture assistant text (debounced) |
| (streaming) | event (file.edited) |
Record file edit observations |
| (compaction) | event (session.compacted) |
Summarize after OpenCode compacts |
Stop |
event (session.idle) |
Flush + summarize + complete |
SessionEnd |
event (session.deleted) |
Flush + complete (no zombie active rows) |
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/health |
Health check |
GET |
/api/context/inject?project={name} |
Fetch formatted memory context |
POST |
/api/sessions/init |
Initialize session |
POST |
/api/sessions/observations |
Store tool observation |
POST |
/api/sessions/summarize |
Trigger summarization |
POST |
/api/sessions/complete |
Complete session |
- Claude Code with Claude-Mem installed
- OpenCode with plugin support
- A running Claude-Mem worker on port
37777(default)
In Claude Code:
/plugin marketplace add thedotmack/claude-mem
/plugin install claude-mem
Restart Claude Code so the worker can start and initialize its data directory.
Add this plugin to your project or global opencode.json:
{
"plugin": ["@ephemushroom/opencode-claude-mem"]
}Then restart OpenCode.
curl -s http://127.0.0.1:37777/api/healthIf the worker is healthy, OpenCode should show a toast like
Memory active · <project> when a session starts.
Once installed, the plugin works automatically:
- Context injection — Memory is injected into the system prompt on each LLM call, with session-level caching to avoid repeated worker requests.
- Compaction preservation — The same cached memory context is pushed into OpenCode’s compaction path so memory survives conversation compression.
- Tool observation capture — Tool executions are stored as observations, except for low-value/meta tools and Claude-Mem search tools.
- Assistant message capture — Assistant text from
message.updatedis buffered with 250ms debounce per session and sent as a singleassistant_messageobservation per turn (avoids streaming-chunk floods). - File edit capture —
file.editedevents are forwarded asfile_editobservations (path only; OpenCode does not include diff in the event). - Session summarization — On
session.compactedandsession.idle, the plugin flushes any pending assistant buffer, fetches the latest user and assistant messages, and asks Claude-Mem to summarize them. - Session lifecycle hygiene — On
session.deletedthe plugin tells the worker tocompleteSession, preventing zombie'active'rows from accumulating stalepending_messages(the "queueDepth never decreases" failure mode).
Memory search is provided by Claude-Mem’s MCP server, not by this plugin.
If your OpenCode environment already has Claude-Mem MCP tools configured, the assistant can query project memory directly with Claude-Mem’s search workflow:
search(query="...")timeline(anchor=ID)get_observations(ids=[...])
This plugin focuses on sending memory data to the worker and injecting returned context back into OpenCode sessions.
- Thin client architecture —
src/index.tshandles OpenCode hooks and session state;src/worker-client.tsis a static HTTP client. - No console logging — The plugin never writes to
console.*because that can corrupt the OpenCode TUI. - Deferred toast — Health toasts only happen after hook execution begins, avoiding startup crashes caused by early TUI access.
- Real prompt initialization —
chat.messagesends the actual user prompt to Claude-Mem instead of a synthetic placeholder. - Real summarize payloads — On
session.idle, the plugin reads the latest session messages and sends the last user and assistant messages for summary. - Context caching — Memory context is fetched once per session and reused across prompt injection and compaction.
- Circular memory protection — Injected context is wrapped in
<claude-mem-context>tags, Claude-Mem MCP search tools are skipped, and memory-related tags are stripped before storing observations. - UTF-8 truncation — Large observation outputs are capped by byte size to reduce token waste and avoid oversize worker payloads.
- Field name correctness — Worker payloads use
contentSessionId, notclaudeSessionId.
This project intentionally stays smaller in scope.
- This plugin does: bridge OpenCode hooks to an already-installed Claude-Mem worker.
- This plugin does not: auto-install Claude-Mem, auto-edit OpenCode config, auto-copy skills, auto-register slash commands, or auto-start the worker.
That keeps the runtime behavior predictable and leaves worker ownership with the upstream Claude-Mem installation.
- Confirm the worker is running:
curl -s http://127.0.0.1:37777/api/health- Make sure Claude-Mem has already been installed and used from Claude Code.
- Start a fresh OpenCode session after the worker is healthy.
The plugin will try to launch the worker via bunx claude-mem start once on
plugin load. If that toast still appears:
- Confirm
bunis on yourPATH—bun --versionshould print a version. - Confirm
claude-memis installed forbunx/npx— runbunx claude-mem --versiononce to populate the cache. - On Windows after a forced kill, port
37777may stay inTIME_WAITfor 30-120 seconds; wait it out or restart Claude Code. - Restart Claude Code to bring Claude-Mem back up via its own supervisor.
- Verify the worker port is still
37777.
- Update to a version with deferred TUI access.
- Ensure there are no
console.log,console.warn, orconsole.errorcalls in local plugin modifications.
- Ensure the worker API payload uses
contentSessionId. - Be aware that low-value meta tools and Claude-Mem search tools are skipped by design.
- Very large tool outputs are truncated before storage.
- This plugin does not configure MCP tools for you.
- Configure Claude-Mem’s MCP server separately in your OpenCode environment if you want in-editor memory search.
bun install
bun run build
bun run lint
bun run fmt:checkIf you edit source code locally, rebuild and restart OpenCode to pick up the new plugin bundle.
MIT