Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e975025747 | ||
|
|
767795d5de | ||
|
|
d7e2a0e7b0 |
@@ -12,7 +12,7 @@
|
||||
"name": "mem0",
|
||||
"source": "./mem0-plugin",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
|
||||
"version": "0.1.2"
|
||||
"version": "0.1.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1326,7 +1326,7 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
|
||||
<Update label="2026-05-14" description="Python v0.2.5 / Node v0.2.5">
|
||||
|
||||
**New Features:**
|
||||
- **Agent Mode (`mem0 init --agent`):** Zero-friction signup for AI agents — mints a working Mem0 API key in under 5 seconds with no email, no dashboard, no OTP. Returns an unclaimed shadow account the human can later claim with `mem0 init --email <their-email>` (memories preserved, same key keeps working) ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Agent Mode (`mem0 init --agent`):** Zero-friction signup for AI agents — mints a working Mem0 API key in <5s with no email, no dashboard, no OTP. Returns an unclaimed shadow account the human can later claim with `mem0 init --email <their-email>` (memories preserved, same key keeps working) ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Self-declared agent identity:** Agents pass `--agent-caller <name>` (e.g. `claude-code`, `cursor`, `codex`) on `mem0 init --agent` so signups attribute to the right tool in analytics. Proof Editor-style — the agent declares itself rather than the CLI sniffing it from env vars ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **`mem0 identify <name>`:** New subcommand to self-tag an Agent Mode key after the fact when the agent forgot to pass `--agent-caller` on init. Idempotent — re-running just overwrites ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
- **Plugin sync:** `~/.claude/settings.json::env::MEM0_API_KEY` and `~/.zshrc`/`.bashrc` `export MEM0_API_KEY=` lines stay in sync with `~/.mem0/config.json` automatically. Idempotent — only updates EXISTING entries, never creates new ones ([#5123](https://github.com/mem0ai/mem0/pull/5123))
|
||||
|
||||
+2
-55
@@ -25,44 +25,7 @@ pip install mem0-cli
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Agent Mode — zero-friction signup for AI agents
|
||||
|
||||
<Tip>
|
||||
**If you're an AI agent reading this**, skip the rest of this page until you've run the command below. Everything else assumes you already have an API key.
|
||||
</Tip>
|
||||
|
||||
AI agents (Claude Code, Cursor, Codex, Cline, Aider, …) can mint a working Mem0 API key in under five seconds with no email, no dashboard, and no OTP:
|
||||
|
||||
```bash
|
||||
mem0 init --agent --agent-caller claude-code
|
||||
```
|
||||
|
||||
Replace `claude-code` with your agent's name (e.g. `cursor`, `codex`, `cline`, `aider`, or any custom string). The CLI saves the key to `~/.mem0/config.json` and prints a notice you should surface to your human user. The human can claim the account later — same API key keeps working, memories transfer.
|
||||
|
||||
<Tip>
|
||||
**Forgot `--agent-caller`?** Run `mem0 identify <your-name>` after init — same key, just back-fills the attribution. Idempotent.
|
||||
</Tip>
|
||||
|
||||
### Claiming an Agent Mode key (humans)
|
||||
|
||||
When the human is ready, they claim ownership of the agent's key by running:
|
||||
|
||||
```bash
|
||||
mem0 init --email you@yourcompany.com
|
||||
```
|
||||
|
||||
The CLI detects the existing unclaimed Agent Mode config, sends a verification code, and upgrades the shadow account in-place: **the API key never changes, all memories transfer to the human's account, and the agent isn't disrupted**. Pass `--code 123456` for fully non-interactive flows.
|
||||
|
||||
### Plugin sync
|
||||
|
||||
When you save a Mem0 API key (any flow — Agent Mode, email, or `--api-key`), the CLI also propagates it to ecosystem touchpoints **that already exist**:
|
||||
|
||||
- `~/.claude/settings.json` → `env.MEM0_API_KEY` (Claude Code plugin env injection)
|
||||
- `~/.zshrc` / `~/.bashrc` → existing `export MEM0_API_KEY=` lines
|
||||
|
||||
Sync is idempotent and **never creates new entries** — it only updates entries you've already set up. Failures are best-effort and never block the canonical write to `~/.mem0/config.json`.
|
||||
|
||||
## Authentication (humans)
|
||||
## Authentication
|
||||
|
||||
Run the interactive setup wizard to configure your API key:
|
||||
|
||||
@@ -116,7 +79,6 @@ Interactive setup wizard. Prompts for your API key and default user ID.
|
||||
mem0 init
|
||||
mem0 init --api-key m0-xxx --user-id alice
|
||||
mem0 init --email alice@company.com
|
||||
mem0 init --agent --agent-caller claude-code # zero-friction signup for AI agents
|
||||
```
|
||||
|
||||
If an existing configuration is detected, the CLI will ask for confirmation before overwriting. Use `--force` to skip the prompt (useful in CI/CD pipelines).
|
||||
@@ -129,25 +91,10 @@ mem0 init --api-key m0-xxx --user-id alice --force
|
||||
|------|-------------|
|
||||
| `--api-key` | API key (skip prompt) |
|
||||
| `-u, --user-id` | Default user ID (skip prompt) |
|
||||
| `--email` | Login via email verification code (also used to claim an Agent Mode key) |
|
||||
| `--email` | Login via email verification code |
|
||||
| `--code` | Verification code (use with `--email` for non-interactive login) |
|
||||
| `--agent` | Bootstrap an Agent Mode account — no email, no dashboard |
|
||||
| `--agent-caller` | Self-declared agent identity for Agent Mode signups (e.g. `claude-code`, `cursor`) |
|
||||
| `--source` | Channel attribution for analytics (e.g. `github`, `hn`, `ph`) |
|
||||
| `--force` | Overwrite existing config without confirmation |
|
||||
|
||||
### `mem0 identify`
|
||||
|
||||
Tag your active Agent Mode key with the AI agent that's using it. Run this once after `mem0 init --agent` if you didn't pass `--agent-caller` on init. Idempotent — re-running just overwrites the value.
|
||||
|
||||
```bash
|
||||
mem0 identify claude-code
|
||||
mem0 identify cursor
|
||||
mem0 identify my-custom-bot
|
||||
```
|
||||
|
||||
The CLI calls `PATCH /api/v1/auth/agent_mode/caller/` against the active key. Only works on unclaimed Agent Mode keys; the backend rejects with 400 otherwise. Agent names are sanitized server-side (lowercased, restricted to `[a-z0-9._/-]`, truncated to 32 chars).
|
||||
|
||||
### `mem0 add`
|
||||
|
||||
Add a memory from text, a JSON messages array, a file, or stdin.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mem0",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows using the Mem0 Platform MCP server.",
|
||||
"author": {
|
||||
"name": "Mem0",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the Mem0 plugin will be documented in this file.
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Fixed
|
||||
|
||||
- **user_id resolution no longer derives from `MEM0_API_KEY`.** v0.1.2 changed the resolver to fall back to `"mem0-" + sha256(MEM0_API_KEY)[:12]` ahead of `$USER`, which silently moved every existing user to a new bucket on update. Memories written under the previous `$USER` value became unreachable from the plugin. Resolution is now back to `MEM0_USER_ID` → `$USER` → `"default"`.
|
||||
- Dropped the "regardless of which machine you're on" line from the SessionStart bootstrap, since cross-machine consolidation now requires setting `MEM0_USER_ID` explicitly.
|
||||
|
||||
### Notes for users upgrading from 0.1.2
|
||||
|
||||
- The `~/.mem0/identity.json` cache file is no longer read or written. Safe to delete.
|
||||
- If you wrote memories during the v0.1.2 window, they live under `mem0-<sha256(api_key)[:12]>`. To recover: temporarily `export MEM0_USER_ID=mem0-<hash>`, search/export, then unset.
|
||||
- Want a single bucket across machines (the original goal of #5076)? Set `MEM0_USER_ID` explicitly in your shell profile. The plugin will not auto-derive one.
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Added
|
||||
|
||||
- Deterministic `user_id` resolver (`_identity.sh` / `_identity.py`) — **reverted in 0.1.3, see above.**
|
||||
- SessionStart-compact handler (`capture_compact_summary.py`) that stores the post-compaction summary as a memory with `metadata.type=compact_summary`.
|
||||
- Coding-taxonomy setup script (`setup_coding_categories.py`) — one-shot `project.update(custom_categories=[...])` for `architecture_decisions`, `anti_patterns`, `task_learnings`, `tooling_setup`, `bug_fixes`, `coding_conventions`, `user_preferences`.
|
||||
- Opt-in hook logging via `MEM0_DEBUG=1` → `~/.mem0/hooks.log`.
|
||||
- `mem0-mcp` skill replacing the Claude-Code-specific `mem0-codex` skill.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `session_id` now written to memory metadata (`on_pre_compact.py`).
|
||||
- SessionStart bootstrap exits silently when `MEM0_API_KEY` is unset.
|
||||
- `block_memory_write.sh` regex tightened to `MEMORY.md` / `.claude/memory/*` — no longer blocks `docs/memory/*.md`.
|
||||
- Removed duplicate PreCompact write path (kept agent-driven, dropped the parallel Python REST entry from `hooks.json` / `cursor-hooks.json`).
|
||||
- Hook-side captures (`session_state`, `compact_summary`) now set `expiration_date = today + 90 days`.
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- Cursor plugin fully functional (`#4547`).
|
||||
- Codex plugin support and integration docs (`#4665`).
|
||||
- Codex lifecycle hooks via opt-in installer (`#4917`).
|
||||
- Removed invalid keys from Claude plugin config (`#4821`).
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Initial release: Mem0 plugin for Claude Code and Cursor (`#4518`).
|
||||
@@ -1,59 +1,17 @@
|
||||
"""Resolve mem0 user_id with deterministic priority.
|
||||
"""Resolve mem0 user_id.
|
||||
|
||||
Resolution priority:
|
||||
1. MEM0_USER_ID env var (explicit override)
|
||||
2. ~/.mem0/identity.json cache (pinned to current MEM0_API_KEY fingerprint)
|
||||
3. Derived: "mem0-" + sha256(MEM0_API_KEY)[:12]
|
||||
4. Fallback: $USER, else "default"
|
||||
|
||||
Same MEM0_API_KEY across machines yields the same user_id, which fixes
|
||||
the "47 user buckets per account" symptom from running on multiple
|
||||
laptops with different $USER values.
|
||||
2. $USER, else "default"
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
_CACHE_PATH = os.path.expanduser("~/.mem0/identity.json")
|
||||
|
||||
|
||||
def resolve_user_id() -> str:
|
||||
explicit = os.environ.get("MEM0_USER_ID", "").strip()
|
||||
if explicit:
|
||||
return explicit
|
||||
|
||||
api_key = os.environ.get("MEM0_API_KEY", "").strip()
|
||||
if api_key:
|
||||
digest = hashlib.sha256(api_key.encode("utf-8")).hexdigest()
|
||||
fingerprint = digest[:8]
|
||||
|
||||
try:
|
||||
with open(_CACHE_PATH, "r") as f:
|
||||
cached = json.load(f)
|
||||
if cached.get("api_key_fingerprint") == fingerprint and cached.get("user_id"):
|
||||
return cached["user_id"]
|
||||
except (OSError, json.JSONDecodeError):
|
||||
pass
|
||||
|
||||
derived = "mem0-" + digest[:12]
|
||||
try:
|
||||
os.makedirs(os.path.dirname(_CACHE_PATH), exist_ok=True)
|
||||
with open(_CACHE_PATH, "w") as f:
|
||||
json.dump(
|
||||
{
|
||||
"user_id": derived,
|
||||
"source": "api_key",
|
||||
"api_key_fingerprint": fingerprint,
|
||||
"resolved_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
},
|
||||
f,
|
||||
)
|
||||
except OSError:
|
||||
pass
|
||||
return derived
|
||||
|
||||
return os.environ.get("USER") or "default"
|
||||
|
||||
@@ -2,54 +2,13 @@
|
||||
#
|
||||
# Resolution priority:
|
||||
# 1. MEM0_USER_ID env var (explicit override)
|
||||
# 2. ~/.mem0/identity.json cache (pinned to current MEM0_API_KEY fingerprint)
|
||||
# 3. Derived: "mem0-" + sha256(MEM0_API_KEY)[:12]
|
||||
# 4. Fallback: $USER, else "default"
|
||||
#
|
||||
# Same MEM0_API_KEY across machines yields the same user_id, which fixes
|
||||
# the "47 user buckets per account" symptom from running on multiple
|
||||
# laptops with different $USER values.
|
||||
|
||||
_mem0_sha256() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum | cut -d' ' -f1
|
||||
else
|
||||
shasum -a 256 | cut -d' ' -f1
|
||||
fi
|
||||
}
|
||||
# 2. $USER, else "default"
|
||||
|
||||
_mem0_resolve_identity() {
|
||||
if [ -n "${MEM0_USER_ID:-}" ]; then
|
||||
printf '%s' "$MEM0_USER_ID"
|
||||
return
|
||||
fi
|
||||
|
||||
local api_key="${MEM0_API_KEY:-}"
|
||||
local cache="$HOME/.mem0/identity.json"
|
||||
|
||||
if [ -n "$api_key" ]; then
|
||||
local digest
|
||||
digest=$(printf '%s' "$api_key" | _mem0_sha256)
|
||||
local fp="${digest:0:8}"
|
||||
|
||||
if [ -f "$cache" ]; then
|
||||
local cached_fp cached_id
|
||||
cached_fp=$(jq -r '.api_key_fingerprint // ""' "$cache" 2>/dev/null)
|
||||
cached_id=$(jq -r '.user_id // ""' "$cache" 2>/dev/null)
|
||||
if [ "$cached_fp" = "$fp" ] && [ -n "$cached_id" ]; then
|
||||
printf '%s' "$cached_id"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
local derived="mem0-${digest:0:12}"
|
||||
mkdir -p "$HOME/.mem0" 2>/dev/null && \
|
||||
printf '{"user_id":"%s","source":"api_key","api_key_fingerprint":"%s","resolved_at":"%s"}\n' \
|
||||
"$derived" "$fp" "$(date -u +%FT%TZ)" > "$cache" 2>/dev/null
|
||||
printf '%s' "$derived"
|
||||
return
|
||||
fi
|
||||
|
||||
printf '%s' "${USER:-default}"
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ echo "## Mem0 Identity"
|
||||
echo ""
|
||||
echo "Active user_id: \`$MEM0_RESOLVED_USER_ID\`"
|
||||
echo ""
|
||||
echo "Always include \`{\"user_id\": \"$MEM0_RESOLVED_USER_ID\"}\` (wrapped in an \`AND\` clause) in every \`search_memories\` filter and as \`user_id\` on every \`add_memory\` call. This keeps memories under one bucket regardless of which machine you're on."
|
||||
echo "Always include \`{\"user_id\": \"$MEM0_RESOLVED_USER_ID\"}\` (wrapped in an \`AND\` clause) in every \`search_memories\` filter and as \`user_id\` on every \`add_memory\` call. This keeps the agent's MCP calls aligned with the bucket the hooks write to."
|
||||
echo ""
|
||||
|
||||
if [ "$SOURCE" = "startup" ]; then
|
||||
|
||||
@@ -4,3 +4,5 @@ __version__ = importlib.metadata.version("mem0ai")
|
||||
|
||||
from mem0.client.main import AsyncMemoryClient, MemoryClient # noqa
|
||||
from mem0.memory.main import AsyncMemory, Memory # noqa
|
||||
|
||||
|
||||
|
||||
@@ -156,3 +156,4 @@ known_first_party = ["mem0", "mem0_cli"]
|
||||
# isort scope kept aligned with [tool.ruff.lint.isort] above.
|
||||
# black-equivalent profile here matches the formatter behaviour ruff applies.
|
||||
# Plugin-version bumps need a touch here to fire required CI checks (path-filter trap).
|
||||
# Last touched: plugin v0.1.3
|
||||
|
||||
Reference in New Issue
Block a user