Relevant source files
The following files were used as context for generating this wiki page:
- integrations/opencode-plugin/opencode-mem0.ts
- integrations/codex-plugin/core/memory_core.py
- integrations/openclaw/index.ts
- integrations/claude-code-plugin/core/memory_core.py
- integrations/agent-plugin-core/python/memory_core.py
- integrations/antigravity-plugin/core/memory_core.py
- integrations/mem0-agent-plugin/core/memory_core.py
- integrations/kimi-plugin/core/memory_core.py
- integrations/deepseek-plugin/src/index.ts
- integrations/hermes-plugin-mem0/init.py
- integrations/cursor-plugin/core/memory_core.py
- integrations/pi-agent-plugin/src/memory/tools.ts
- integrations/codex-plugin/core/mcp_server.py
- integrations/kimi-plugin/core/mcp_server.py
- integrations/antigravity-plugin/core/mcp_server.py
- integrations/claude-code-plugin/hooks/hooks.json
- integrations/codex-plugin/hooks/hooks.json
- integrations/claude-code-plugin/core/mcp_server.py
- integrations/mem0-agent-plugin/core/mcp_server.py
- integrations/agent-plugin-core/python/mcp_server.py
- integrations/pi-agent-plugin/src/entry.ts
- integrations/cursor-plugin/core/mcp_server.py
- integrations/opencode-plugin/api-key.ts
- integrations/opencode-plugin/project.ts
- integrations/opencode-plugin/scope.ts
Overview
The Mem0 OpenCode integration exposes persistent semantic memory directly inside OpenCode agent sessions integrations/opencode-plugin/opencode-mem0.ts:2-5. Operating via the mem0ai SDK without requiring a separate Model Context Protocol (MCP) server, it wires memory management into OpenCode plugin hooks to capture and recall facts across sessions integrations/opencode-plugin/opencode-mem0.ts:2-5. Credentials are resolved hierarchically from process environments and user shell profiles, while project identity is derived robustly from Git remotes and repository root paths integrations/opencode-plugin/opencode-mem0.ts:32-51, integrations/opencode-plugin/api-key.ts:15-29. Furthermore, the subsystem normalizes memory scopes and search filters to partition memories by project, session, or global boundaries, and intercepts turn hooks to inject relevant memory contexts into agent prompts integrations/opencode-plugin/opencode-mem0.ts:17, integrations/opencode-plugin/scope.ts:12-33.
Sources: integrations/opencode-plugin/opencode-mem0.ts:2-5, integrations/opencode-plugin/opencode-mem0.ts:17, integrations/opencode-plugin/opencode-mem0.ts:32-51, integrations/opencode-plugin/api-key.ts:15-29, integrations/opencode-plugin/scope.ts:12-33
OpenCode Plugin Architecture and Lifecycle
Initialization and SDK Wiring
The OpenCode plugin acts as the public entry point for memory integration, exporting a standard Plugin interface that wires native memory tools backed directly by the mem0ai SDK without requiring an intermediate Model Context Protocol server integrations/opencode-plugin/opencode-mem0.ts:2-8. During startup, the plugin resolves ambient environment variables such as MEM0_USER_ID and MEM0_APP_ID, falling back to operating system username and Git repository metadata when explicit configuration is absent integrations/opencode-plugin/opencode-mem0.ts:23-51. It integrates with the TypeScript agent lifecycle by invoking createMemoryLifecycle from the common agent core, binding turn interception hooks, and initializing project-level coding categories against the Mem0 platform integrations/opencode-plugin/opencode-mem0.ts:20, integrations/opencode-plugin/opencode-mem0.ts:115-149.
Note
The OpenCode plugin bypasses MCP transport layers entirely, instantiating the MemoryClient directly in TypeScript to register native tools for adding, searching, and managing memories integrations/opencode-plugin/opencode-mem0.ts:4-8.
Sources: integrations/opencode-plugin/opencode-mem0.ts:2-8, integrations/opencode-plugin/opencode-mem0.ts:20, integrations/opencode-plugin/opencode-mem0.ts:23-51, integrations/opencode-plugin/opencode-mem0.ts:115-149
Lifecycle Constants and Matching Patterns
The plugin evaluates conversation turns against pre-compiled regular expressions and category fingerprints to determine when to trigger memory capture, project state synchronization, or context resumption integrations/opencode-plugin/opencode-mem0.ts:98-160.
| Constant Name | Type | Value / Pattern | Purpose |
|---|---|---|---|
CODING_CATEGORIES | string[] | 17 standard categories (architecture_decisions, api_design, etc.) | Defines custom project categories synchronized via autoSetupCategories integrations/opencode-plugin/opencode-mem0.ts:98-104 |
NUDGE_RE | RegExp | `/\b(remember\s+(this | that) |
RESUME_RE | RegExp | `/where\s+(did\s+)?(we | I)\s+(leave |
ERROR_STRONG_RE | RegExp | /Traceback \(most recent call last\)|panic: |.../ | Matches critical runtime errors and panics in tool outputs integrations/opencode-plugin/opencode-mem0.ts:157-158 |
WRITE_TOOLS | Set<string> | ["Write", "Edit", "MultiEdit", "write", "edit", "multiEdit"] | Identifies file-modifying tools that trigger automatic memory flushing integrations/opencode-plugin/opencode-mem0.ts:160 |
Sources: integrations/opencode-plugin/opencode-mem0.ts:98-104, integrations/opencode-plugin/opencode-mem0.ts:151-160
API Key Resolution and Authentication
Credential Resolution Strategy
The OpenCode plugin resolves API keys hierarchically, checking active runtime environment variables before scanning user shell profile files in the home directory integrations/opencode-plugin/api-key.ts:15-27. The resolveApiKey function first inspects env.MEM0_API_KEY (defaulting to process.env), returning the explicit value immediately if present and non-empty integrations/opencode-plugin/api-key.ts:15-17. When no explicit environment variable is configured, the resolver iterates through a fixed sequence of user profile files located in the user's home directory integrations/opencode-plugin/api-key.ts:5, integrations/opencode-plugin/api-key.ts:19-27.
Note
If all candidate profile files are missing, unreadable, or contain no valid export statements, resolveApiKey falls back to returning an empty string integrations/opencode-plugin/api-key.ts:25-29.
Sources: integrations/opencode-plugin/api-key.ts:5-29
Profile Parsing and Environment Files
When inspecting user shell configurations, the resolver evaluates each line of a profile file using parseApiKeyLine to extract assignment expressions integrations/opencode-plugin/api-key.ts:7-13, integrations/opencode-plugin/api-key.ts:19-24. The parser matches lines containing optional export keywords followed by MEM0_API_KEY=, strips inline comments and enclosing single or double quotes, and rejects values that reference unexpanded shell variables beginning with a dollar sign integrations/opencode-plugin/api-key.ts:7-12.
| Profile File / Source | Target Variable | Parsing Rules | Fallback Behavior |
|---|---|---|---|
process.env | MEM0_API_KEY | Direct trimmed string evaluation | Proceeds to filesystem profiles if undefined or empty integrations/opencode-plugin/api-key.ts:15-17 |
.zshrc | MEM0_API_KEY | Matches export MEM0_API_KEY=..., strips # comments & quotes integrations/opencode-plugin/api-key.ts:5-13 | Skips file on read errors, continues sequence integrations/opencode-plugin/api-key.ts:19-27 |
.bashrc | MEM0_API_KEY | Matches export MEM0_API_KEY=..., strips # comments & quotes integrations/opencode-plugin/api-key.ts:5-13 | Skips file on read errors, continues sequence integrations/opencode-plugin/api-key.ts:19-27 |
.zprofile | MEM0_API_KEY | Matches export MEM0_API_KEY=..., strips # comments & quotes integrations/opencode-plugin/api-key.ts:5-13 | Skips file on read errors, continues sequence integrations/opencode-plugin/api-key.ts:19-27 |
.bash_profile | MEM0_API_KEY | Matches export MEM0_API_KEY=..., strips # comments & quotes integrations/opencode-plugin/api-key.ts:5-13 | Skips file on read errors, continues sequence integrations/opencode-plugin/api-key.ts:19-27 |
.profile | MEM0_API_KEY | Matches export MEM0_API_KEY=..., strips # comments & quotes integrations/opencode-plugin/api-key.ts:5-13 | Returns "" if exhausted without match integrations/opencode-plugin/api-key.ts:25-29 |
Sources: integrations/opencode-plugin/api-key.ts:5-29
Workspace Project Identity Extraction
Project Identity Derivation Logic
The OpenCode workspace derives its unique project identifier by evaluating runtime environment variables, git repository remotes, and local working directory structures integrations/opencode-plugin/opencode-mem0.ts:32-51. The getProjectId function first inspects process.env.MEM0_APP_ID, returning this explicit configuration immediately if present integrations/opencode-plugin/opencode-mem0.ts:33. When no application ID environment variable is defined, the function executes a series of asynchronous shell commands via the tagged template literal $ to query git state integrations/opencode-plugin/opencode-mem0.ts:34-41.
Note
Git remote parsing extracts the repository's owner and repository name, providing an identity that remains stable across clones, worktrees, and custom host aliases integrations/opencode-plugin/opencode-mem0.ts:34-39.
async function getProjectId($: any): Promise<string> {
if (process.env.MEM0_APP_ID) return process.env.MEM0_APP_ID;
// Prefer the git remote's owner/repo — stable across clones, worktrees, and
// sub-directories (handles https + ssh, incl. custom host aliases).
try {
const r = await $`git remote get-url origin`.quiet();
const project = parseProjectFromRemote(r.stdout.toString());
if (project) return project;
} catch {
}
// No usable remote: use the git repo ROOT dir name, not cwd (which may be a
// sub-directory, or your home dir if OpenCode was launched outside a repo).
try {
const r = await $`git rev-parse --show-toplevel`.quiet();
const top = r.stdout.toString().trim();
if (top) return basename(top);
} catch {
}
return basename(process.cwd());
}Sources: integrations/opencode-plugin/opencode-mem0.ts:32-51
Fallback Resolution and Branch Detection
When a git remote is unavailable or parsing fails, getProjectId attempts to locate the repository root via git rev-parse --show-toplevel and extracts its basename integrations/opencode-plugin/opencode-mem0.ts:42-49. This prevents sub-directories or home directory launches from polluting project scopes integrations/opencode-plugin/opencode-mem0.ts:42-43. If all git queries fail, the function falls back to the basename of the current working directory (process.cwd()) integrations/opencode-plugin/opencode-mem0.ts:50. Concurrently, branch identification is handled by getBranch, which executes git branch --show-current and defaults to "main" if the command throws an error or yields an empty string integrations/opencode-plugin/opencode-mem0.ts:53-60.
| Resolution Method | Command / Source | Target Property | Fallback Behavior |
|---|---|---|---|
| Environment Override | process.env.MEM0_APP_ID | Project Identifier | Proceeds to git remote check if undefined integrations/opencode-plugin/opencode-mem0.ts:33 |
| Git Remote Parsing | git remote get-url origin | Owner/Repository | Proceeds to repository root discovery on failure integrations/opencode-plugin/opencode-mem0.ts:37-41 |
| Repository Root | git rev-parse --show-toplevel | Top-level Basename | Falls back to process.cwd() basename integrations/opencode-plugin/opencode-mem0.ts:45-51 |
| Branch Detection | git branch --show-current | Current Git Branch | Defaults to "main" if detached or non-git directory integrations/opencode-plugin/opencode-mem0.ts:55-59 |
export { parseProjectFromRemote } from "../agent-plugin-core/typescript/src/identity.ts";Sources: integrations/opencode-plugin/opencode-mem0.ts:32-60, integrations/opencode-plugin/project.ts:1-1
Scope Normalization and Search Filtering
Scoping Parameters and Default Resolution
Memory read and write operations are governed by scope configurations that dictate whether memories apply globally, to the current project, or to an active session. The scope subsystem normalizes user preferences and applies runtime parameters using shared utilities from the TypeScript agent core integrations/opencode-plugin/scope.ts:1-6. The resolveDefaultScope function inspects user settings stored in ~/.mem0/settings.json, falling back to standard scoping rules via normalizeScope integrations/opencode-plugin/opencode-mem0.ts:74-96, integrations/opencode-plugin/scope.ts:37-39.
Sources: integrations/opencode-plugin/opencode-mem0.ts:74-96, integrations/opencode-plugin/scope.ts:1-6, integrations/opencode-plugin/scope.ts:37-39
Tip
The default scope reads fresh from persistent settings on every operation, allowing users to modify their active scope via the mem0-scope skill without restarting OpenCode integrations/opencode-plugin/opencode-mem0.ts:89-96.
Scope Guidance and Filter Adaptation
Memory tools rely on explicit scope instructions defined by SCOPE_GUIDANCE, which directs agents on when to omit the scope parameter for normal queries, restrict it to the current run using "session", or escalate to "global" after user authorization integrations/opencode-plugin/scope.ts:41-42. Search filters and write parameters adapt these scopes into concrete identifiers using scopeSearchFilters and scopeWriteParams integrations/opencode-plugin/scope.ts:12-33.
| Scope Function | Input Parameters | Return Structure | Purpose |
|---|---|---|---|
scopeSearchFilters | scope, userId, appId, runId | Record<string, string> | Builds search query filters matching the active scope level integrations/opencode-plugin/scope.ts:12-19 |
scopeWriteParams | scope, userId, appId, runId | { user_id: string; app_id?: string; run_id?: string } | Formats parameters for memory storage operations integrations/opencode-plugin/scope.ts:21-33 |
asScope | Raw scope input | Scope | Normalizes arbitrary scope strings via core utilities integrations/opencode-plugin/scope.ts:35 |
resolveDefaultScope | settings object | Scope | Extracts and normalizes default scope from settings file integrations/opencode-plugin/scope.ts:37-39 |
export function scopeSearchFilters(
scope: Scope,
userId: string,
appId: string,
runId: string,
): Record<string, string> {
return sharedSearchFilters(scope, context(userId, appId, runId));
}
export function scopeWriteParams(
scope: Scope,
userId: string,
appId: string,
runId: string,
): { user_id: string; app_id?: string; run_id?: string } {
const values = scopeAddParams(scope, context(userId, appId, runId));
return {
user_id: values.userId,
...(values.appId ? { app_id: values.appId } : {}),
...(values.runId ? { run_id: values.runId } : {}),
};
}
export const asScope = normalizeScope;
export function resolveDefaultScope(settings: Record<string, unknown> | null | undefined): Scope {
return normalizeScope(settings?.default_scope);
}Sources: integrations/opencode-plugin/scope.ts:12-39
Turn Hooks and Memory Injection
Interception Hooks and Message Extraction
Conversation streams and agent turns in OpenCode are intercepted through lifecycle hooks that monitor session flow, extract relevant user text, and manage background capture or prompt assembly integrations/deepseek-plugin/src/index.ts:130-198. Regular expressions such as NUDGE_RE detect explicit user memory directives like "remember this", "memorize", or "don't forget", while RESUME_RE identifies patterns for continuing previous work like "where did we leave off" or "catch me up" integrations/opencode-plugin/opencode-mem0.ts:151-156. Additionally, error patterns such as ERROR_STRONG_RE capture stack traces and compiler panics (Traceback (most recent call last), panic:, FATAL:, error[E\d+:]) to trigger automated memory preservation integrations/opencode-plugin/opencode-mem0.ts:157-159.
const NUDGE_RE =
/\b(remember\s+(this|that)|memorize|save\s+this|note\s+(this|that)|don'?t\s+forget|always\s+remember|never\s+forget|keep\s+(this|that)\s+in\s+(mind|memory)|store\s+(this|that))\b/i;
const RESUME_RE =
/where\s+(did\s+)?(we|I)\s+(leave|left)\s+off|continue\s+(from\s+)?(where|last)|what\s+were\s+we\s+(working|doing)|pick\s+up\s+where|resume\s+(from\s+|where\s+)|what.s\s+the\s+(current|latest)\s+(state|status)|catch\s+me\s+up|where\s+are\s+we/i;
const ERROR_STRONG_RE =
/Traceback \(most recent call last\)|panic: |FATAL:|error\[E\d+\]/;
const ERROR_MULTI_RE = /(Error:|Exception:)/g;
const WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit", "write", "edit", "multiEdit"]);Sources: integrations/opencode-plugin/opencode-mem0.ts:151-160
Warning
Write tools such as Write, Edit, and MultiEdit (tracked in WRITE_TOOLS) modify codebase state and require careful handling during conversation captures to prevent duplicating raw file diffs into long-term semantic memory integrations/opencode-plugin/opencode-mem0.ts:160.
Prompt Compaction and Context Injection
Prompt assembly phases leverage the TypeScript agent core lifecycle (createMemoryLifecycle) to prepare conversation histories and sanitize user inputs before executing semantic similarity searches against the Mem0 platform integrations/deepseek-plugin/src/index.ts:110-144. When a user prompt is submitted, the system filters out non-user message sources, strips extraneous metadata, and prepares the text for recall integrations/deepseek-plugin/src/index.ts:136-140. Retrieved memory results are formatted with clear section headers and injected directly into the system prompt context array under descriptors like mem0:recall or <relevant-memories> integrations/deepseek-plugin/src/index.ts:166-169, integrations/openclaw/index.ts:685.
ctx.on("system-prompt/assemble", async (_input, context, next): Promise<PromptAssembly> => {
const assembly = await next();
const { agent, signal } = context;
if (!agent || signal?.aborted) return assembly;
const state = stateFor(agent.session);
const prompt = state.lifecycle.prepareConversation(
agent.session
.deriveMessages()
.filter((message) => message.role === "user" && message.source?.kind === "user"),
).at(-1)?.content;
if (!prompt) return assembly;
const memoryContext = await state.lifecycle.recall(prompt, true, async (query) => {
const started = Date.now();
try {
const result = await client.search(query, {
filters: resolveSearchFilters({}, userId),
topK: AUTO_RECALL_LIMIT,
});
captureEvent("deepseek.recall.auto", {
success: true,
duration_ms: Date.now() - started,
result_count: result.results?.length ?? 0,
}, client);
return result;
} catch (err) {
captureEvent("deepseek.recall.auto", {
success: false,
duration_ms: Date.now() - started,
error_kind: errorKind(err),
}, client);
throw err;
}
});
if (!memoryContext || signal?.aborted) return assembly;
return {
...assembly,
contexts: [...assembly.contexts, { name: "mem0:recall", text: memoryContext }],
};
});Sources: integrations/deepseek-plugin/src/index.ts:130-170, integrations/openclaw/index.ts:685
Related
On This Page
OverviewOpenCode Plugin Architecture and LifecycleInitialization and SDK WiringLifecycle Constants and Matching PatternsAPI Key Resolution and AuthenticationCredential Resolution StrategyProfile Parsing and Environment FilesWorkspace Project Identity ExtractionProject Identity Derivation LogicFallback Resolution and Branch DetectionScope Normalization and Search FilteringScoping Parameters and Default ResolutionScope Guidance and Filter AdaptationTurn Hooks and Memory InjectionInterception Hooks and Message ExtractionPrompt Compaction and Context InjectionRelated