Skip to main content
doc0blade47/mem0documentation home
Sign in

IDE Plugins Family

Last updated Oct 11, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

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 KeyValue TemplatePurpose
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 EventMatcherCommand TemplateTimeout (s)
SessionStart—python3 ./hooks/adapter.py SessionStart5
UserPromptSubmit—python3 ./hooks/adapter.py UserPromptSubmit6
PostToolUse.*python3 ./hooks/adapter.py PostToolUse3
PostToolUseFailure.*python3 ./hooks/adapter.py PostToolUseFailure3
Stop—python3 ./hooks/adapter.py Stop3
PreCompact—python3 ./hooks/adapter.py PreCompact5
SessionEnd—python3 ./hooks/adapter.py SessionEnd5

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 PathTarget DestinationPurpose
.cursor-plugin/plugin.json.cursor-plugin/plugin.jsonHost extension registration metadata
hooks/hooks.jsonhooks/hooks.jsonLifecycle event hook mappings
hooks/adapter.pyhooks/adapter.pyPython adapter translating host payloads
mcp.jsonmcp.jsonModel 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 value

Sources: 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 HostNative Event / ActionNormalized Target ActionKey Field Normalization
KimiSessionStartsession-startMaps script argument directly
KimiUserPromptSubmituser-promptExtracts additional context for injection
KimiStopstopResolves wire transcript for last_assistant_message
CursorsessionStartsession-startSets session_id from conversation identifiers
CursorbeforeSubmitPromptuser-promptNormalizes workspace_roots[0] to cwd
CursorafterAgentResponseassistant-stopMaps text or summary to last_assistant_message
AntigravityPreInvocationsession-start / user-promptParses transcriptPath for user prompt and assistant text
AntigravityPostToolUsepost-tool / post-tool-failureUnpacks toolCall name and args
Codexpost-toolcodex-post-toolEvaluates 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

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 True

Sources: 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 NameDefault ValuePurpose
STALE_RUNNING_SECONDS300Threshold in seconds before a running handoff lock is considered stale
PENDING_EXPIRY_SECONDS604800 (7 days)Maximum retention age for pending handoff payload files
PENDING_LAUNCH_LIMIT5Maximum number of recovered handoffs launched in a single batch
DEFAULT_IDLE_FLUSH_SECONDS300Default 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 IntegrationHARNESS_IDSOURCE_TAGPLATFORM_SOURCEPLATFORM_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 True

Sources: 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 FunctionPrimary VariableFallback VariablesDefault Value / Pathing
data_dir()MEM0_CODE_DATA_DIRMEM0_PLUGIN_DATA_DIR, PLUGIN_DATA, CLAUDE_PLUGIN_DATA~/.mem0/{_harness_data_dir_name}
user_id()PLUGIN_OPTION_USER_ID, MEM0_CODE_USER_IDMEM0_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()
            raise

Sources: 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

Was this page helpful?