feat(claude-code-plugin): move the Claude Code plugin to its own integration and ship it as 0.3.0 (#7106)
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "mem0",
|
||||
"version": "0.2.15",
|
||||
"description": "Persistent memory for Claude Code. Remembers decisions, patterns, and preferences across sessions.",
|
||||
"author": {
|
||||
"name": "Mem0",
|
||||
"email": "support@mem0.ai"
|
||||
},
|
||||
"homepage": "https://mem0.ai",
|
||||
"repository": "https://github.com/mem0ai/mem0",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": ["memory", "personalization", "mcp", "semantic-search"],
|
||||
"userConfig": {
|
||||
"api_key": {
|
||||
"type": "string",
|
||||
"title": "Mem0 API Key",
|
||||
"description": "Your Mem0 Platform API key (starts with m0-). Get one at https://app.mem0.ai/dashboard/api-keys",
|
||||
"sensitive": true,
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem0": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.mem0.ai/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Token ${MEM0_API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
# Mem0 Plugin for Claude Code, Claude Cowork, Cursor, Codex, OpenCode & Antigravity
|
||||
> **Claude Code users:** version 0.3.0 of the Claude Code plugin now lives at
|
||||
> [`integrations/claude-code-plugin`](../claude-code-plugin/) and is what `mem0@mem0-plugins` installs.
|
||||
> Update with `claude plugin marketplace update mem0-plugins` then
|
||||
> `claude plugin update mem0@mem0-plugins --scope user` — your memories carry over
|
||||
> automatically. This directory continues to serve the Cursor, Codex, Kimi,
|
||||
> Antigravity, and OpenCode integrations until they are ported. The Claude Code
|
||||
> manifest, hooks, and MCP config have been removed from this directory, so
|
||||
> there is nothing here left to install into Claude Code.
|
||||
|
||||
Add persistent memory to your AI workflows. Store, retrieve, and manage memories across sessions using the Mem0 Platform. Works with **Claude Code** (CLI), **Claude Cowork** (desktop app), **Cursor**, **Codex**, **OpenCode**, and **Antigravity**.
|
||||
# Mem0 Plugin for Cursor, Codex, Kimi, OpenCode & Antigravity
|
||||
|
||||
Add persistent memory to your AI workflows. Store, retrieve, and manage memories across sessions using the Mem0 Platform. Works with **Cursor**, **Codex**, **Kimi**, **OpenCode**, and **Antigravity**. For Claude Code, use [`integrations/claude-code-plugin`](../claude-code-plugin/).
|
||||
|
||||
## Quick path for agents
|
||||
|
||||
@@ -52,21 +61,6 @@ Humans setting up Mem0 by hand should continue with Step 1 below.
|
||||
|
||||
Choose one of the options below. All require `MEM0_API_KEY` to be set first (see above).
|
||||
|
||||
### Claude Code (CLI) / Claude Cowork (Desktop)
|
||||
|
||||
Claude Code and Claude Cowork share the same plugin system.
|
||||
|
||||
**CLI:**
|
||||
|
||||
```
|
||||
/plugin marketplace add mem0ai/mem0
|
||||
/plugin install mem0@mem0-plugins
|
||||
```
|
||||
|
||||
**Cowork desktop app:** Open the Cowork tab, click **Customize** in the sidebar, click **Browse plugins**, and install Mem0.
|
||||
|
||||
This installs the full plugin including the MCP server, lifecycle hooks (automatic memory capture), and the Mem0 SDK skill.
|
||||
|
||||
### Codex
|
||||
|
||||
**Option A — Direct MCP** (fastest, MCP only):
|
||||
@@ -191,7 +185,7 @@ This runs the setup wizard which:
|
||||
3. Installs coding-optimized memory categories
|
||||
4. Shows your identity (user ID, project scope, branch)
|
||||
|
||||
The onboarding is idempotent — safe to re-run anytime. On first session in a new project (0 memories), Claude is prompted to run it automatically.
|
||||
The onboarding is idempotent — safe to re-run anytime. On first session in a new project (0 memories), the agent is prompted to run it automatically.
|
||||
|
||||
## Verify it works
|
||||
|
||||
@@ -224,27 +218,26 @@ The plugin includes 17 skills accessible via `/mem0:` commands:
|
||||
|
||||
## What's included
|
||||
|
||||
| Component | Claude Code / Cowork | Cursor (MCP) | Codex (Sideload) | Codex (Direct MCP) | OpenCode (Full) | OpenCode (MCP) | Antigravity |
|
||||
|-----------|:--------------------:|:------------:|:----------------:|:------------------:|:---------------:|:--------------:|:-----------:|
|
||||
| MCP Server | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| Lifecycle Hooks | Yes | No | Opt-in | No | Yes | No | Yes |
|
||||
| Mem0 SDK Skill | Yes | No | Yes | No | Yes | No | Yes |
|
||||
| Component | Cursor (MCP) | Codex (Sideload) | Codex (Direct MCP) | OpenCode (Full) | OpenCode (MCP) | Antigravity |
|
||||
|-----------|:------------:|:----------------:|:------------------:|:---------------:|:--------------:|:-----------:|
|
||||
| MCP Server | Yes | Yes | Yes | Yes | Yes | Yes |
|
||||
| Lifecycle Hooks | No | Opt-in | No | Yes | No | Yes |
|
||||
| Mem0 SDK Skill | No | Yes | No | Yes | No | Yes |
|
||||
|
||||
- **MCP Server** — Connects to the Mem0 remote MCP server (`mcp.mem0.ai`), providing tools to add, search, update, and delete memories. No local dependencies required.
|
||||
- **Lifecycle Hooks** — Automatic memory capture at key points. Claude Code, OpenCode, and Antigravity wire hooks natively when the full plugin is installed. Codex hooks are opt-in via a one-time installer (`scripts/install_codex_hooks.py`).
|
||||
- **Lifecycle Hooks** — Automatic memory capture at key points. OpenCode and Antigravity wire hooks natively when the full plugin is installed. Codex hooks are opt-in via a one-time installer (`scripts/install_codex_hooks.py`).
|
||||
- **Mem0 SDK Skill** — Guides the AI on how to integrate the Mem0 SDK (Python & TypeScript) into your applications.
|
||||
|
||||
## Updating the plugin
|
||||
|
||||
When the plugin updates (new version pulled from the marketplace, or a fresh local install), the MCP server connection in your existing session is left holding a stale handle and stops responding. **Restart your client to reconnect:**
|
||||
|
||||
- **Claude Code:** run `/restart` in the prompt, or close and reopen the CLI.
|
||||
- **Cursor:** quit and relaunch.
|
||||
- **Codex:** restart the editor session.
|
||||
- **OpenCode:** restart the session.
|
||||
- **Antigravity:** restart the session.
|
||||
|
||||
Your `MEM0_API_KEY` doesn't need to be re-entered — the auth header is re-read from your environment on the new session. The plugin's MCP config uses `${MEM0_API_KEY}` interpolation at session start, not at install time, so as long as the env var is set persistently (in your shell profile or `~/.claude/settings.json` `env` block), reconnection is automatic on restart.
|
||||
Your `MEM0_API_KEY` doesn't need to be re-entered — the auth header is re-read from your environment on the new session. The plugin's MCP config uses `${MEM0_API_KEY}` interpolation at session start, not at install time, so as long as the env var is set persistently (in your shell profile), reconnection is automatic on restart.
|
||||
|
||||
If reconnection still fails after a restart, check that `MEM0_API_KEY` is reachable in the new shell (`echo $MEM0_API_KEY`) and confirm you're using a key that starts with `m0-` (from https://app.mem0.ai/dashboard/api-keys, not a legacy token).
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"hooks": {
|
||||
"Setup": [
|
||||
{
|
||||
"matcher": "init|maintenance",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/ensure_deps.sh",
|
||||
"statusMessage": "Installing mem0 SDK...",
|
||||
"timeout": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SessionStart": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/requirements.txt\" \"${CLAUDE_PLUGIN_DATA:-$HOME/.mem0/plugin-data}/requirements.txt\" >/dev/null 2>&1 || \"${CLAUDE_PLUGIN_ROOT}/scripts/ensure_deps.sh\"",
|
||||
"statusMessage": "Installing mem0 SDK...",
|
||||
"timeout": 60
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "startup|resume|compact",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_session_start.sh",
|
||||
"statusMessage": "Loading mem0 context..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Write|Edit|MultiEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/block_memory_write.sh"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "mcp__mem0__add_memory|mcp__plugin_mem0_mem0__add_memory|mcp__mem0__search_memories|mcp__plugin_mem0_mem0__search_memories|mcp__mem0__get_memories|mcp__plugin_mem0_mem0__get_memories|mcp__mem0__delete_all_memories|mcp__plugin_mem0_mem0__delete_all_memories",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/enforce_metadata_defaults.sh",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Read",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_file_read.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "mcp__mem0__.*|mcp__plugin_mem0_mem0__.*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_post_tool_use.sh",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_bash_output.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_stop.sh",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_pre_compact.sh",
|
||||
"statusMessage": "Preparing pre-compaction summary..."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/on_user_prompt.sh",
|
||||
"statusMessage": "Checking memory relevance...",
|
||||
"timeout": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -27,20 +27,20 @@ import urllib.error
|
||||
import urllib.request
|
||||
|
||||
# Each editor surface ships its own manifest with its own version line
|
||||
# (Antigravity is on 0.1.x while Claude/Cursor/Codex are on 0.2.x), so we read
|
||||
# the manifest matching the detected platform rather than a single shared one.
|
||||
# (Antigravity is on 0.1.x while Cursor/Codex are on 0.2.x), so we read the
|
||||
# manifest matching the detected platform rather than a single shared one.
|
||||
_PLATFORM_MANIFESTS = {
|
||||
"antigravity": ("..", "plugin.json"),
|
||||
"claude-code": ("..", ".claude-plugin", "plugin.json"),
|
||||
"cursor": ("..", ".cursor-plugin", "plugin.json"),
|
||||
"codex": ("..", ".codex-plugin", "plugin.json"),
|
||||
"kimi": ("..", ".kimi-plugin", "plugin.json"),
|
||||
}
|
||||
_DEFAULT_MANIFEST = ("..", ".claude-plugin", "plugin.json")
|
||||
|
||||
|
||||
def _load_plugin_version(platform_name: str = "") -> str:
|
||||
parts = _PLATFORM_MANIFESTS.get(platform_name, _DEFAULT_MANIFEST)
|
||||
parts = _PLATFORM_MANIFESTS.get(platform_name)
|
||||
if parts is None:
|
||||
return "unknown"
|
||||
try:
|
||||
plugin_json = os.path.join(os.path.dirname(__file__), *parts)
|
||||
with open(plugin_json) as f:
|
||||
@@ -79,8 +79,6 @@ def detect_platform() -> str:
|
||||
return "kimi"
|
||||
if os.environ.get("PLUGIN_ROOT"):
|
||||
return "codex"
|
||||
if os.environ.get("CLAUDECODE") or os.environ.get("CLAUDE_PLUGIN_ROOT"):
|
||||
return "claude-code"
|
||||
if os.environ.get("CURSOR_PLUGIN_ROOT"):
|
||||
return "cursor"
|
||||
if os.environ.get("WINDSURF_PLUGIN_ROOT"):
|
||||
|
||||
@@ -122,24 +122,12 @@ def test_hash_deterministic():
|
||||
assert h1 != telemetry._sha256("different-value")
|
||||
|
||||
|
||||
def test_platform_claude_code(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CURSOR_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.setenv("CLAUDECODE", "1")
|
||||
assert telemetry.detect_platform() == "claude-code"
|
||||
|
||||
|
||||
def test_platform_cursor(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CLAUDECODE", raising=False)
|
||||
monkeypatch.delenv("CLAUDE_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.setenv("CURSOR_PLUGIN_ROOT", "/path")
|
||||
assert telemetry.detect_platform() == "cursor"
|
||||
@@ -150,7 +138,6 @@ def test_platform_codex(monkeypatch):
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CLAUDECODE", raising=False)
|
||||
monkeypatch.delenv("CLAUDE_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CURSOR_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.setenv("PLUGIN_ROOT", "/path")
|
||||
@@ -165,7 +152,6 @@ def test_platform_kimi(monkeypatch):
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
monkeypatch.delenv("ANTIGRAVITY_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CLAUDECODE", raising=False)
|
||||
monkeypatch.delenv("CLAUDE_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("CURSOR_PLUGIN_ROOT", raising=False)
|
||||
monkeypatch.delenv("PLUGIN_ROOT", raising=False)
|
||||
@@ -184,8 +170,8 @@ def test_platform_explicit_override(monkeypatch):
|
||||
|
||||
|
||||
def test_platform_antigravity(monkeypatch):
|
||||
"""Antigravity sets CLAUDE_PLUGIN_ROOT for compatibility but must be
|
||||
attributed to its own platform, not claude-code."""
|
||||
"""Antigravity sets CLAUDE_PLUGIN_ROOT so the shared scripts resolve their
|
||||
paths. That must not change how it is attributed."""
|
||||
import telemetry
|
||||
|
||||
monkeypatch.delenv("MEM0_PLATFORM", raising=False)
|
||||
@@ -196,14 +182,14 @@ def test_platform_antigravity(monkeypatch):
|
||||
|
||||
def test_plugin_version_is_per_editor(monkeypatch):
|
||||
"""Each editor reports the version from its OWN manifest. Antigravity is on
|
||||
a 0.1.x line while Claude/Cursor/Codex are on 0.2.x, so they must not all
|
||||
report the same shared version."""
|
||||
a 0.1.x line while Cursor/Codex are on 0.2.x, so they must not all report
|
||||
the same shared version. An unsupported surface reports "unknown" rather
|
||||
than borrowing a version it does not ship."""
|
||||
import telemetry
|
||||
|
||||
plugin_dir = os.path.join(os.path.dirname(__file__), "..")
|
||||
manifests = {
|
||||
"antigravity": "plugin.json",
|
||||
"claude-code": os.path.join(".claude-plugin", "plugin.json"),
|
||||
"cursor": os.path.join(".cursor-plugin", "plugin.json"),
|
||||
"codex": os.path.join(".codex-plugin", "plugin.json"),
|
||||
"kimi": os.path.join(".kimi-plugin", "plugin.json"),
|
||||
@@ -215,6 +201,10 @@ def test_plugin_version_is_per_editor(monkeypatch):
|
||||
payload = telemetry.build_posthog_payload("plugin.test")
|
||||
assert payload["properties"]["plugin_version"] == expected, f"{plat} should report {expected} from {rel}"
|
||||
|
||||
monkeypatch.setenv("MEM0_PLATFORM", "claude-code")
|
||||
payload = telemetry.build_posthog_payload("plugin.test")
|
||||
assert payload["properties"]["plugin_version"] == "unknown"
|
||||
|
||||
|
||||
def test_send_fails_silently(monkeypatch):
|
||||
import telemetry
|
||||
|
||||
Reference in New Issue
Block a user