Relevant source files
The following files were used as context for generating this wiki page:
- integrations/codex-plugin/hooks/hooks.json
- integrations/antigravity-plugin/hooks.json
- integrations/cursor-plugin/mcp.json
- integrations/opencode-plugin/opencode-mem0.ts
- integrations/kimi-plugin/hooks/adapter.py
- integrations/cursor-plugin/hooks/hooks.json
- integrations/cursor-plugin/hooks/adapter.py
- integrations/kimi-plugin/kimi.plugin.json
- integrations/antigravity-plugin/hooks/adapter.py
- integrations/codex-plugin/.mcp.json
- integrations/codex-plugin/hooks/adapter.py
- integrations/cursor-plugin/core/hook_runner.py
- integrations/codex-plugin/core/memory_core.py
- integrations/kimi-plugin/core/hook_runner.py
- integrations/codex-plugin/core/hook_runner.py
- integrations/claude-code-plugin/.mcp.json
- integrations/antigravity-plugin/core/hook_runner.py
- integrations/claude-code-plugin/core/hook_runner.py
- integrations/cursor-plugin/core/memory_core.py
- integrations/antigravity-plugin/core/memory_core.py
- integrations/claude-code-plugin/hooks/hooks.json
- integrations/antigravity-plugin/core/_harness_id.py
- integrations/kimi-plugin/core/memory_core.py
- integrations/antigravity-plugin/mcp_config.json
- integrations/cursor-plugin/plugin-build.json
- integrations/agent-plugin-core/python/hook_runner.py
- integrations/kimi-plugin/core/_harness_id.py
- integrations/cursor-plugin/core/_harness_id.py
- integrations/claude-code-plugin/core/memory_core.py
- integrations/claude-code-plugin/adapters/claude/hook.py
Overview
The IDE plugins family integrates Mem0 memory persistence directly into developer coding environments integrations/kimi-plugin/kimi.plugin.json:1-12, including OpenCode Integration and the Claude Code Plugin. These integrations solve the fragmentation of context across sessions by capturing prompts, tool executions, and transcript streams, bridging editor hooks integrations/cursor-plugin/hooks/adapter.py:2-3 with the Python Agent Core. Key design decisions include unified harness identifiers, normalized event adapters integrations/kimi-plugin/hooks/adapter.py:85-100, and Model Context Protocol (MCP) server declarations integrations/cursor-plugin/mcp.json:2-17 to synchronize long-term memory across hosts.
Sources: integrations/kimi-plugin/kimi.plugin.json:1-12, integrations/cursor-plugin/hooks/adapter.py:2-3, integrations/kimi-plugin/hooks/adapter.py:85-100, integrations/cursor-plugin/mcp.json:2-17
IDE MCP Server Manifest Specifications
Cursor Environment Manifest
The Cursor plugin configures the mem0 Model Context Protocol server via mcp.json, declaring a stdio transport type executing python3 with path resolution tied to ${CURSOR_PLUGIN_ROOT}. Environment variables pass template parameters for API authentication and memory scoping directly to the underlying server process.
{
"mcpServers": {
"mem0": {
"type": "stdio",
"command": "python3",
"args": [
"${CURSOR_PLUGIN_ROOT}/core/mcp_server.py"
],
"env": {
"PLUGIN_OPTION_API_KEY": "${api_key}",
"PLUGIN_OPTION_USER_ID": "${user_id}",
"PLUGIN_OPTION_TOP_K": "${top_k}",
"PLUGIN_OPTION_MAX_CONTEXT_CHARS": "${max_context_chars}",
"PLUGIN_OPTION_SEARCH_SCOPE": "${search_scope}"
}
}
}
}Sources: integrations/cursor-plugin/mcp.json:1-18
| Option Key | Value Template | Purpose |
|---|---|---|
PLUGIN_OPTION_API_KEY | ${api_key} | Authentication token for memory service requests |
PLUGIN_OPTION_USER_ID | ${user_id} | User scope identifier for stored memories |
PLUGIN_OPTION_TOP_K | ${top_k} | Result count limit for memory retrieval queries |
PLUGIN_OPTION_MAX_CONTEXT_CHARS | ${max_context_chars} | Character threshold governing context injection size |
PLUGIN_OPTION_SEARCH_SCOPE | ${search_scope} | Boundary filter applied during memory searches |
Sources: integrations/cursor-plugin/mcp.json:9-15
Note
Cursor relies on explicit ${CURSOR_PLUGIN_ROOT} path interpolation within args to locate mcp_server.py relative to the installed plugin bundle directory.
Sources: integrations/cursor-plugin/mcp.json:5-8
Codex Environment Manifest
The Codex plugin declares its MCP server configuration within .mcp.json, setting a working directory (cwd) of . alongside an explicit array of allowed environment variable names rather than interpolated option templates.
{
"mcpServers": {
"mem0": {
"type": "stdio",
"command": "python3",
"args": ["./core/mcp_server.py"],
"cwd": ".",
"env_vars": [
"MEM0_API_KEY",
"MEM0_API_URL",
"MEM0_CODE_USER_ID",
"MEM0_USER_ID",
"MEM0_RESOLVED_USER_ID",
"MEM0_PROJECT_ID",
"MEM0_TELEMETRY"
]
}
}
}Sources: integrations/codex-plugin/.mcp.json:1-18
Important
Codex uses the env_vars array specification to whitelist environment variables (MEM0_API_KEY, MEM0_API_URL, MEM0_CODE_USER_ID, MEM0_USER_ID, MEM0_RESOLVED_USER_ID, MEM0_PROJECT_ID, MEM0_TELEMETRY) to be passed through to the Python MCP server process.
Sources: integrations/codex-plugin/.mcp.json:8-16
Antigravity Environment Manifest
The Antigravity plugin uses a streamlined mcp_config.json manifest structure that omits explicit transport type declarations, environment maps, and working directories, launching python3 with a relative script path.
{
"mcpServers": {
"mem0": {
"command": "python3",
"args": ["./core/mcp_server.py"]
}
}
}Sources: integrations/antigravity-plugin/mcp_config.json:1-8
Warning
Omitting type: "stdio" and environment block definitions means Antigravity relies entirely on process inheritance for runtime configuration and default transport bindings.
Sources: integrations/antigravity-plugin/mcp_config.json:1-8
Plugin Metadata and Host Declarations
Kimi Plugin Definition
The Kimi extension is defined by kimi.plugin.json, specifying metadata, package keywords, an Apache-2.0 license, and integration interfaces for Kimi Code. It registers a Model Context Protocol (MCP) server running python3 with ./core/mcp_server.py, alongside an array of event hooks with specific execution timeouts.
{
"name": "mem0",
"version": "0.3.3",
"description": "Cross-session memory and token savings for coding agents.",
"keywords": ["memory", "coding-agents", "continual-learning", "token-efficiency"],
"author": { "name": "Mem0", "email": "support@mem0.ai" },
"homepage": "https://docs.mem0.ai/integrations/kimi",
"license": "Apache-2.0",
"interface": {
"displayName": "Mem0",
"shortDescription": "Cross-session memory for Kimi Code"
},
"skills": "./skills/",
"mcpServers": {
"mem0": {
"command": "python3",
"args": ["./core/mcp_server.py"]
}
},
"hooks": [
{ "event": "SessionStart", "command": "python3 ./hooks/adapter.py SessionStart", "timeout": 5 },
{ "event": "UserPromptSubmit", "command": "python3 ./hooks/adapter.py UserPromptSubmit", "timeout": 6 },
{ "event": "PostToolUse", "matcher": ".*", "command": "python3 ./hooks/adapter.py PostToolUse", "timeout": 3 },
{ "event": "PostToolUseFailure", "matcher": ".*", "command": "python3 ./hooks/adapter.py PostToolUseFailure", "timeout": 3 },
{ "event": "Stop", "command": "python3 ./hooks/adapter.py Stop", "timeout": 3 },
{ "event": "PreCompact", "command": "python3 ./hooks/adapter.py PreCompact", "timeout": 5 },
{ "event": "SessionEnd", "command": "python3 ./hooks/adapter.py SessionEnd", "timeout": 5 }
]
}Sources: integrations/kimi-plugin/kimi.plugin.json:1-28
| Hook Event | Matcher | Command Template | Timeout (s) |
|---|---|---|---|
SessionStart | — | python3 ./hooks/adapter.py SessionStart | 5 |
UserPromptSubmit | — | python3 ./hooks/adapter.py UserPromptSubmit | 6 |
PostToolUse | .* | python3 ./hooks/adapter.py PostToolUse | 3 |
PostToolUseFailure | .* | python3 ./hooks/adapter.py PostToolUseFailure | 3 |
Stop | — | python3 ./hooks/adapter.py Stop | 3 |
PreCompact | — | python3 ./hooks/adapter.py PreCompact | 5 |
SessionEnd | — | python3 ./hooks/adapter.py SessionEnd | 5 |
Sources: integrations/kimi-plugin/kimi.plugin.json:20-28
Note
Kimi hook registrations rely on direct script invocations via python3 ./hooks/adapter.py paired with capitalized event selectors.
Sources: integrations/kimi-plugin/kimi.plugin.json:20-28
Cursor Packaging and Native Build Configuration
Cursor plugin builds are managed via plugin-build.json, which sets the package identifier to mem0, version 0.3.3, and links to the Cursor documentation homepage. The native manifest maps the plugin root directory ${CURSOR_PLUGIN_ROOT} to specific bundle assets required for distribution.
{
"id": "mem0",
"version": "0.3.3",
"homepage": "https://docs.mem0.ai/integrations/cursor",
"native": {
"pluginRoot": "${CURSOR_PLUGIN_ROOT}",
"files": {
".cursor-plugin/plugin.json": ".cursor-plugin/plugin.json",
"hooks/hooks.json": "hooks/hooks.json",
"hooks/adapter.py": "hooks/adapter.py",
"mcp.json": "mcp.json"
}
}
}Sources: integrations/cursor-plugin/plugin-build.json:1-13
| Bundled Asset Path | Target Destination | Purpose |
|---|---|---|
.cursor-plugin/plugin.json | .cursor-plugin/plugin.json | Host extension registration metadata |
hooks/hooks.json | hooks/hooks.json | Lifecycle event hook mappings |
hooks/adapter.py | hooks/adapter.py | Python adapter translating host payloads |
mcp.json | mcp.json | Model Context Protocol server configuration |
Sources: integrations/cursor-plugin/plugin-build.json:7-12
Caution
The packaging manifest strictly requires all four bundled files under native.files; omitting any file path during compilation causes runtime initialization failures within the Cursor environment.
Sources: integrations/cursor-plugin/plugin-build.json:5-13
Host Hook Adapters and Normalization
Payload Translation and Transcript Parsing
Each IDE environment delivers lifecycle hooks and transcript files with distinct payloads. The host adapters translate these platform-specific structures into normalized arguments and key-value fields consumed by the shared Mem0 runtime.
The Kimi plugin adapter maps native events such as SessionStart, UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, PreCompact, and SessionEnd to shared actions, normalizing field variations where tool_output or error populates tool_response, and response sets last_assistant_message. When processing Stop events, the adapter resolves the session directory from KIMI_CODE_HOME or ~/.kimi-code using session_index.jsonl or directory scanning, locates the agent wire transcript at agents/main/wire.jsonl, parses assistant message loops, and injects the latest assistant response.
EVENTS = {
"SessionStart": ["session-start"],
"UserPromptSubmit": ["user-prompt"],
"PostToolUse": ["post-tool"],
"PostToolUseFailure": ["post-tool-failure"],
"Stop": ["stop"],
"PreCompact": ["flush", "--reason", "pre-compact"],
"SessionEnd": ["flush", "--reason", "session-end"],
}
def _session_dir(session_id: str) -> Path | None:
home = Path(os.environ.get("KIMI_CODE_HOME", Path.home() / ".kimi-code")).expanduser()
found = None
try:
with (home / "session_index.jsonl").open(encoding="utf-8") as index:
for line in index:
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
if entry.get("sessionId") == session_id and isinstance(entry.get("sessionDir"), str):
found = Path(entry["sessionDir"])
except OSError:
pass
if found:
return found
if not session_id or Path(session_id).name != session_id:
return None
return next((path for path in (home / "sessions").glob(f"*/{session_id}") if path.is_dir()), None)
def _last_assistant_message(transcript: Path) -> str:
message = ""
step_id = None
parts = []
try:
lines = transcript.read_text(encoding="utf-8").splitlines()
except OSError:
return ""
for line in lines:
try:
record = json.loads(line)
except json.JSONDecodeError:
continue
if record.get("type") != "context.append_loop_event" or not isinstance(record.get("event"), dict):
continue
event = record["event"]
if event.get("type") == "step.begin":
step_id = event.get("uuid")
parts = []
elif event.get("type") == "content.part" and event.get("stepUuid") == step_id:
part = event.get("part")
if isinstance(part, dict) and part.get("type") == "text" and isinstance(part.get("text"), str):
parts.append(part["text"])
elif event.get("type") == "step.end" and event.get("uuid") == step_id:
if event.get("finishReason") not in {"error", "interrupted"} and parts:
message = "".join(parts)
step_id = None
parts = []
return message
def normalize(payload: dict) -> dict:
value = dict(payload)
if "tool_output" in value:
value.setdefault("tool_response", value["tool_output"])
if "error" in value:
value.setdefault("tool_response", value["error"])
if "response" in value:
value.setdefault("last_assistant_message", value["response"])
if value.get("hook_event_name") == "Stop":
session = _session_dir(str(value.get("session_id") or ""))
transcript = session / "agents" / "main" / "wire.jsonl" if session else None
if transcript and transcript.is_file():
value.setdefault("transcript_path", str(transcript))
if message := _last_assistant_message(transcript):
value.setdefault("last_assistant_message", message)
return valueSources: integrations/kimi-plugin/hooks/adapter.py:22-100
The Cursor adapter translates camelCase native events into kebab-case actions, standardizing session identification across conversation_id and parent_conversation_id, mapping workspace_roots to working directories (cwd), and normalizing tool_output or error_message into tool_response.
EVENTS = {
"sessionStart": "session-start",
"beforeSubmitPrompt": "user-prompt",
"postToolUse": "post-tool",
"postToolUseFailure": "post-tool-failure",
"afterAgentResponse": "assistant-stop",
"stop": "stop",
"sessionEnd": "session-end",
"preCompact": "pre-compact",
}
def normalize(payload: dict, event: str) -> dict:
value = dict(payload)
value.setdefault("session_id", value.get("conversation_id") or value.get("parent_conversation_id", ""))
roots = value.get("workspace_roots") or []
if roots:
value.setdefault("cwd", roots[0])
if "tool_output" in value:
value.setdefault("tool_response", value["tool_output"])
if "error_message" in value:
value.setdefault("tool_response", value["error_message"])
if "text" in value:
value.setdefault("last_assistant_message", value["text"])
if "summary" in value:
value.setdefault("last_assistant_message", value["summary"])
return {"action": EVENTS[event], "payload": value}Sources: integrations/cursor-plugin/hooks/adapter.py:25-51
The Antigravity adapter reads structured step transcripts, filtering entries where status equals DONE and type is USER_INPUT or PLANNER_RESPONSE, extracting redacted content inside <USER_REQUEST> tags for prompts and plain text for assistant planner responses.
def _subagent_start(store, hook_input):
context = record_subagent_start(store, hook_input)
if context:
return {
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": context,
}
}
def _subagent_stop(store, hook_input):
record_subagent_stop(store, hook_input)
def _post_tool(store, payload):
response = payload.get("tool_response")
failed = None
if isinstance(response, dict):
exit_code = response.get("exit_code")
if isinstance(exit_code, int) and not isinstance(exit_code, bool):
failed = exit_code != 0
elif isinstance(response.get("isError"), bool):
failed = response["isError"]
elif isinstance(response.get("success"), bool):
failed = not response["success"]
if failed:
payload = {**payload, "error": response}
record_tool(store, payload, failed=failed)
Sources: integrations/antigravity-plugin/hooks/adapter.py:28-48, integrations/codex-plugin/hooks/adapter.py:27-56
Note
The Codex adapter intercepts post-tool arguments, normalizing tool responses that return dictionaries with exit_code, isError, or success keys into explicit failure flags before passing payloads to record_tool.
Sources: integrations/codex-plugin/hooks/adapter.py:42-56
Event Routing and Field Mapping Matrix
| IDE Host | Native Event / Action | Normalized Target Action | Key Field Normalization |
|---|---|---|---|
| Kimi | SessionStart | session-start | Maps script argument directly |
| Kimi | UserPromptSubmit | user-prompt | Extracts additional context for injection |
| Kimi | Stop | stop | Resolves wire transcript for last_assistant_message |
| Cursor | sessionStart | session-start | Sets session_id from conversation identifiers |
| Cursor | beforeSubmitPrompt | user-prompt | Normalizes workspace_roots[0] to cwd |
| Cursor | afterAgentResponse | assistant-stop | Maps text or summary to last_assistant_message |
| Antigravity | PreInvocation | session-start / user-prompt | Parses transcriptPath for user prompt and assistant text |
| Antigravity | PostToolUse | post-tool / post-tool-failure | Unpacks toolCall name and args |
| Codex | post-tool | codex-post-tool | Evaluates response exit codes and error flags |
Sources: integrations/kimi-plugin/hooks/adapter.py:22-100, integrations/cursor-plugin/hooks/adapter.py:25-51, integrations/antigravity-plugin/hooks/adapter.py:78-97, integrations/codex-plugin/hooks/adapter.py:42-60
Warning
If an Antigravity payload lacks a valid working directory (cwd), the adapter bypasses runtime execution entirely, returning an empty JSON object or a default allow decision to prevent hook timeouts.
Sources: integrations/antigravity-plugin/hooks/adapter.py:126-131
Shared Hook Orchestration Lifecycle
Input Reading and Default Stops
The hook runner reads incoming JSON hook payloads directly from standard input via read_hook_input(), safely guarding against decoding errors or missing streams.
def read_hook_input() -> dict:
try:
value = json.load(sys.stdin)
return value if isinstance(value, dict) else {}
except (json.JSONDecodeError, OSError):
return {}
Sources: integrations/cursor-plugin/core/hook_runner.py:44-50
When recording agent stops without external transcript parsing, default_record_stop() extracts the session identifier, resolves the active repository, redacts the assistant response message, and records it to the evidence store.
def default_record_stop(store: EvidenceStore, hook_input: dict):
"""Record the assistant's response without transcript parsing."""
session_id = _session_id(hook_input)
repo = store.repo_for_session(session_id, hook_input.get("cwd"))
message = redact(hook_input.get("last_assistant_message", "")).strip()
if message:
store.record_assistant_response(repo, session_id, message)
return repo, session_id
Sources: integrations/cursor-plugin/core/hook_runner.py:52-60
First-Prompt Memory Search
Before an agent processes the initial user prompt in a session, first_prompt_memory_output() executes a conditional search over historical repository memories.
def first_prompt_memory_output(store: EvidenceStore, hook_input: dict) -> dict:
"""Search once before the agent handles the first prompt in a session."""
repo, session_id, prompt, is_first_prompt = record_user_prompt(store, hook_input)
if not is_first_prompt:
return {}
try:
minimum_query_chars = int(os.environ.get("MEM0_CODE_MIN_QUERY_CHARS", "20"))
except ValueError:
minimum_query_chars = 20
if len(prompt.strip()) < max(minimum_query_chars, 1):
return {}
result = search_memories(
store, repo, session_id, bounded(prompt, 6000),
top_k=5, operation="first-prompt-search", timeout=2,
)
if not result.memories:
return {}
context = format_context(
result.memories,
"Mem0 found these relevant memories from earlier work in this repository:",
)
telemetry.record(
"context_injected",
repo=repo, session_id=session_id, trigger="first-prompt",
memory_count=len(result.memories), context_chars=len(context),
prompt_chars=len(prompt),
)
return {
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": context,
},
}Sources: integrations/cursor-plugin/core/hook_runner.py:62-94
Note
The first-prompt search strictly requires is_first_prompt to be true and enforces a minimum query length derived from MEM0_CODE_MIN_QUERY_CHARS (defaulting to 20 characters) before querying stored memories with a timeout of 2 seconds.
Sources: integrations/cursor-plugin/core/hook_runner.py:64-76
Periodic Checkpoint Scheduling
Periodic flushing and background process handoffs coordinate asynchronous state persistence during active sessions.
def schedule_periodic_checkpoint(
store: EvidenceStore, hook_input: dict, repo, session_id: str,
) -> bool:
if (
not automatic_flush_enabled()
or not api_key()
or not store.checkpoint_due(repo.identity, session_id)
):
return False
if store.prepare_flush(repo, session_id, "periodic") is None:
return False
hand_off_flush(hook_input, "periodic")
return TrueSources: integrations/cursor-plugin/core/hook_runner.py:199-211
Warning
Periodic checkpoint scheduling is conditional: it requires automatic flushing to be enabled via environment configuration, an active API key to be present, and a checkpoint to be explicitly due for the session identity.
Sources: integrations/cursor-plugin/core/hook_runner.py:202-206
Lifecycle Configuration Constants
| Constant Name | Default Value | Purpose |
|---|---|---|
STALE_RUNNING_SECONDS | 300 | Threshold in seconds before a running handoff lock is considered stale |
PENDING_EXPIRY_SECONDS | 604800 (7 days) | Maximum retention age for pending handoff payload files |
PENDING_LAUNCH_LIMIT | 5 | Maximum number of recovered handoffs launched in a single batch |
DEFAULT_IDLE_FLUSH_SECONDS | 300 | Default idle duration required before triggering an automatic background flush |
Sources: integrations/cursor-plugin/core/hook_runner.py:36-39
Host Identity and Bundle Generation
Harness Identity Constants
Generated harness identity modules establish host-specific constants distinguishing IDE environments within shared agent core distributions. Each target plugin maintains an auto-generated configuration mapping its harness identifier, source tag, and platform application vocabulary.
| Plugin Integration | HARNESS_ID | SOURCE_TAG | PLATFORM_SOURCE | PLATFORM_APPLICATION |
|---|---|---|---|---|
| Antigravity | "antigravity" | "ANTIGRAVITY_PLUGIN" | "MEM0_PLUGIN" | "antigravity" |
| Kimi | "kimi" | "KIMI_PLUGIN" | "MEM0_PLUGIN" | "kimi" |
| Cursor | "cursor" | "CURSOR_PLUGIN" | "MEM0_PLUGIN" | "cursor" |
Sources: integrations/antigravity-plugin/core/_harness_id.py:3-11, integrations/kimi-plugin/core/_harness_id.py:3-11, integrations/cursor-plugin/core/_harness_id.py:3-11
Note
The platform-side vocabulary treats the entire plugin family as a single source (MEM0_PLUGIN), while PLATFORM_APPLICATION identifies the specific editor host context. If the host application is unknown or empty, memory_core omits the application header entirely rather than transmitting a placeholder value.
Sources: integrations/antigravity-plugin/core/_harness_id.py:6-11, integrations/kimi-plugin/core/_harness_id.py:6-11, integrations/cursor-plugin/core/_harness_id.py:6-11
Host Memory State and Ephemeral Storage
API Key and Data Directory Resolution
Host plugins manage configuration state and caching via environment variables and local files. The API key caching subsystem inspects multiple fallback locations to locate credentials, and clears cached token files when all configuration sources are exhausted.
"""Drop the cached key file once every configured key source is gone."""
configured = (
os.environ.get("MEM0_API_KEY")
or os.environ.get("PLUGIN_OPTION_API_KEY")
or os.environ.get("CLAUDE_PLUGIN_OPTION_API_KEY")
or os.environ.get("CLAUDE_PLUGIN_OPTION_MEM0_API_KEY")
or ""
).strip()
if configured:
return False
path = data_dir() / "api-key"
if not path.exists():
return False
try:
path.unlink()
except OSError:
return False
return TrueSources: integrations/codex-plugin/core/memory_core.py:431-448, integrations/cursor-plugin/core/memory_core.py:431-448, integrations/antigravity-plugin/core/memory_core.py:431-448, integrations/kimi-plugin/core/memory_core.py:431-448
Warning
The credential removal utility clear_stale_api_key_cache verifies that every environment configuration vector (MEM0_API_KEY, PLUGIN_OPTION_API_KEY, CLAUDE_PLUGIN_OPTION_API_KEY, and CLAUDE_PLUGIN_OPTION_MEM0_API_KEY) is completely unset before unlinking the local cached api-key file.
Sources: integrations/codex-plugin/core/memory_core.py:432-448, integrations/cursor-plugin/core/memory_core.py:432-448, integrations/antigravity-plugin/core/memory_core.py:432-448, integrations/kimi-plugin/core/memory_core.py:432-448
Storage paths and scoping parameters rely on environment overrides with explicit fallback precedence.
| Option Function | Primary Variable | Fallback Variables | Default Value / Pathing |
|---|---|---|---|
data_dir() | MEM0_CODE_DATA_DIR | MEM0_PLUGIN_DATA_DIR, PLUGIN_DATA, CLAUDE_PLUGIN_DATA | ~/.mem0/{_harness_data_dir_name} |
user_id() | PLUGIN_OPTION_USER_ID, MEM0_CODE_USER_ID | MEM0_USER_ID, MEM0_RESOLVED_USER_ID, USER, USERNAME | "default" |
Sources: integrations/codex-plugin/core/memory_core.py:470-490, integrations/cursor-plugin/core/memory_core.py:470-490, integrations/antigravity-plugin/core/memory_core.py:470-490, integrations/kimi-plugin/core/memory_core.py:470-490
SQLite Evidence Store and Checkpointing
Local persistence relies on an SQLite-backed EvidenceStore configured with write-ahead logging and busy timeout protections.
class EvidenceStore:
def __init__(self, path: Path | None = None):
directory = data_dir() if path is None else path.parent
directory.mkdir(parents=True, exist_ok=True)
self.path = path or directory / "evidence.sqlite3"
try:
self._open()
except sqlite3.DatabaseError:
self._quarantine()
self._open()
def _open(self) -> None:
self.conn = sqlite3.connect(self.path, timeout=10)
self.conn.row_factory = sqlite3.Row
try:
self.conn.execute("PRAGMA journal_mode=WAL")
self.conn.execute("PRAGMA busy_timeout=10000")
self._migrate()
except sqlite3.DatabaseError:
self.conn.close()
raiseSources: integrations/codex-plugin/core/memory_core.py:555-575, integrations/cursor-plugin/core/memory_core.py:555-575, integrations/antigravity-plugin/core/memory_core.py:555-575, integrations/kimi-plugin/core/memory_core.py:555-575
Note
If a database error occurs during initialization, the EvidenceStore automatically quarantines the corrupted database file before attempting to recreate and reopen a clean SQLite store.
Sources: integrations/codex-plugin/core/memory_core.py:560-564, integrations/cursor-plugin/core/memory_core.py:560-564, integrations/antigravity-plugin/core/memory_core.py:560-564, integrations/kimi-plugin/core/memory_core.py:560-564
Transcript events are processed to extract checkpoint text payloads through _checkpoint_message, which handles user prompts, assistant stops, and subagent or sidekick termination messages while applying redaction.
def _checkpoint_message(event: dict[str, Any]) -> str:
kind = event.get("kind")
payload = event.get("payload") or {}
if kind == "user_prompt":
return redact(payload.get("text", "")).strip()
if kind == "assistant_stop":
transcript_messages = payload.get("transcript_messages") or []
if isinstance(transcript_messages, list):
text = "\n".join(
str(message.get("content") or "")
for message in transcript_messages
if isinstance(message, dict) and message.get("content")
)
if text:
return text
return redact(payload.get("text", "")).strip()
if kind in {"subagent_stop", "sidekick_stop"}:
return redact(payload.get("final_message", "")).strip()
return ""Sources: integrations/codex-plugin/core/memory_core.py:509-527, integrations/cursor-plugin/core/memory_core.py:509-527, integrations/antigravity-plugin/core/memory_core.py:509-527, integrations/kimi-plugin/core/memory_core.py:509-527
Related
On This Page
OverviewIDE MCP Server Manifest SpecificationsCursor Environment ManifestCodex Environment ManifestAntigravity Environment ManifestPlugin Metadata and Host DeclarationsKimi Plugin DefinitionCursor Packaging and Native Build ConfigurationHost Hook Adapters and NormalizationPayload Translation and Transcript ParsingEvent Routing and Field Mapping MatrixShared Hook Orchestration LifecycleInput Reading and Default StopsFirst-Prompt Memory SearchPeriodic Checkpoint SchedulingLifecycle Configuration ConstantsHost Identity and Bundle GenerationHarness Identity ConstantsHost Memory State and Ephemeral StorageAPI Key and Data Directory ResolutionSQLite Evidence Store and CheckpointingRelated