Files
mem0/integrations/opencode-plugin
Saket Aryan c05556f3cf fix(plugins): stop the TypeScript telemetry losing events and misattributing accounts
The Python plugin telemetry was hardened across #7322 to #7326. The TypeScript
side has the same defect classes and was not touched, because the two share no
code: agent-plugin-core/python generates into six bundles, agent-plugin-core/
typescript is a separate core each plugin wraps. Fixing one surfaced nothing
about the other, which is how this survived.

Three fixes, all confirmed by running the code rather than reading it.

A failed delivery deleted the batch. The core detached the queue before the
await and swallowed the error, so one blip destroyed the events with nothing
recording that it happened. Probed: two events in, delivery throws, queue goes to
zero, no retry ever. The batch is now put back, bounded by maxQueueSize and
biased to the newest so a long outage costs the oldest events rather than
unbounded memory, and repeated failures back off to a ceiling instead of retrying
every flush against a host that is blocking us. Every event now carries a uuid
stamped at capture, which is what makes the retry safe: PostHog collapses
anything it already accepted.

Deliberately no disk spool, and that is written into the code so it reads as a
decision. Python spools because its hooks are per-tool-call processes that exit
immediately. These plugins live inside a host for a whole session, so
re-queueing covers the same transient failures without the claim and lease
machinery that took three review rounds to get right on the Python side. What it
leaves uncovered is narrow: a session that both starts and ends offline.

openclaw used a cached email forever. The refresh was guarded by !hasEmail, so
after an API key change every event kept reporting under the previous account.
The email is now bound to a fingerprint of the key it was resolved for and only
used while those agree; a mismatch forgets the account and re-resolves. The
resolution latch is per key rather than once per process, so a key changed
mid-session is actually looked up. A row with an email and no fingerprint, which
is what an upgrade from the current version looks like, is verified rather than
adopted, matching the decision reached on #7325.

opencode hashed the project id unsalted, which is reversible for anyone who can
enumerate project ids. Salted with the API key rather than a stored per-install
value: it is already in play, it is high entropy, and it needs no new file and so
no write race to get wrong. Per account rather than per machine, which also keeps
joins working across machines, and it resets on key rotation consistently with
distinctId, which already did.

Also wired opencode's tests into CI. They existed and nothing ran them, so the
regression test asked for on #7322 would not have gated anything.

Verified: agent-plugin-core/ts 30, openclaw 431, opencode 35, pi-agent 89,
deepseek 47. The new tests were each checked against the unfixed code first; the
core ones fail 3 of 3 and the openclaw one fails without the fingerprint gate.

Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb
2026-09-17 18:43:27 +05:30
..

@mem0/opencode-plugin

Persistent memory for OpenCode. Your agent remembers decisions, preferences, and learnings across sessions automatically.

Current package version: 0.3.0. This native TypeScript integration keeps its own tools and scopes while sharing redaction and lifecycle utilities with agent-plugin-core.

Sidekick is available only in the Claude Code plugin.

Install

opencode plugin @mem0/opencode-plugin

This adds the plugin to your ~/.config/opencode/opencode.json. The plugin registers its memory tools and skills. No MCP server configuration is needed.

Or let your agent do it: paste this into OpenCode:

Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/integrations/opencode-plugin/README.md

Get your API key (free): app.mem0.ai/dashboard/api-keys

echo 'export MEM0_API_KEY="m0-your-key"' >> ~/.zshrc && source ~/.zshrc

Restart OpenCode.

What's included

Component Description
10 Native Memory Tools add_memory, search_memories, get_memories, update_memory, delete_memory, and more, backed by the mem0ai SDK
Lifecycle Hooks Auto-search on session start and every prompt, error memory lookup, compaction context, secret redaction
7 Skills /mem0-remember, /mem0-tour, /mem0-search, /mem0-status, /mem0-scope, /mem0-forget, /mem0-context-loader. Discovered through OpenCode's skills.paths

Hooks

Written in TypeScript. Memory operations are native OpenCode tools backed by the mem0ai SDK directly.

Hook Event What it does
Config config Registers the /mem0-* slash commands (via config.command) and adds the plugin's own opencode-skills/ dir to OpenCode's skills.paths for skill discovery without copying files
Chat message chat.message Loads prior memories on session start, searches relevant memories before each prompt, auto-captures learnings periodically
Pre-tool tool.execute.before Blocks MEMORY.md writes, steering them to the add_memory tool
Post-tool tool.execute.after Scans bash errors and pre-fetches related memories
Messages transform experimental.chat.messages.transform Injects memory context (session memories, search results, error lookups) into the prompt
Compaction experimental.session.compacting Stores session state memory, then injects prior memories into compaction context
Shell env shell.env Exports MEM0_USER_ID, MEM0_APP_ID, MEM0_SESSION_ID, and MEM0_BRANCH to shell

Memory Tools

Tool Description
add_memory Save text or conversation history
search_memories Semantic search across memories
get_memories List memories with filters and pagination
get_memory Retrieve a specific memory by ID
update_memory Overwrite a memory's text by ID
delete_memory Delete a single memory by ID
delete_all_memories Bulk delete all memories in scope
delete_entities Delete an entity and its memories
list_entities List users/agents/apps stored in Mem0
get_event_status Check the processing status of an asynchronous memory event

Memory scope

add_memory, search_memories, get_memories, and delete_all_memories accept an optional scope. You can set the default scope (used when none is passed) with the /mem0-scope skill:

Scope Reads Writes
project (default) this repo (user_id + app_id) this repo
session this run (adds run_id) this run
global all your projects (filtered by your user ID) user-wide (drops app_id)
/mem0-scope            # show the current default scope
/mem0-scope global     # save & search across all your projects by default
/mem0-scope project    # back to repo-only (default)

The default persists in ~/.mem0/settings.json (default_scope) and is read fresh on each memory operation, so changes apply without a restart. delete_all_memories always requires an explicit scope="global" to delete user-wide, so changing the default can't trigger a cross-project wipe.

Capture and session context

Automatic capture saves every third qualifying user prompt. Other exchanges and assistant conclusions can be saved through add_memory or the remember skill; this is not a complete transcript recorder. Captured and explicitly saved text is redacted without the former 6,000-character cutoff.

Automatic capture uses the user and repository IDs, with the session ID in metadata. Explicit session-scope writes and searches use the top-level run_id filter. A session-scoped search therefore does not automatically include project memories that only carry metadata.session_id.

These project/session/global scopes are specific to this integration, not the Python plugins' repo/dir/mine scopes. Global tool access requires the user to enable it through /mem0-scope global or plugin settings first.

Verify

Start OpenCode and ask: "Search my memories for recent decisions"

If the mem0 tools respond, you're all set.

Troubleshooting

Problem Fix
No tools appearing Restart OpenCode after installing
401 Unauthorized Check that MEM0_API_KEY is set to a valid key without printing it
Plugin not loading Run opencode plugin @mem0/opencode-plugin again

License

Apache-2.0