Compare commits

..
Author SHA1 Message Date
Mgeeeek d233da8245 chore: remove redundant trailing newlines in mem0/__init__.py
Cleans up the placeholder blank lines added in the earlier CI trigger
commit (#5123). Side-effect: this commit touches mem0/** so it satisfies
the ci.yml path filter and unblocks the required build_mem0 /
build_embedchain checks for this docs PR.
2026-05-14 21:32:29 +05:30
Mgeeeek 4d99e5cc41 docs(cli): add Agent Mode + mem0 identify to /platform/cli
PR #5123 added Agent Mode to the CLI but only updated docs/changelog/sdk.mdx;
the main feature page at docs/platform/cli.mdx (which renders at
https://docs.mem0.ai/platform/cli) still documented only the pre-Agent-Mode
commands.

Changes:
- New "Agent Mode — zero-friction signup for AI agents" section placed
  ABOVE regular Authentication, since it's the primary entry point for
  agent users and the page promo positions the CLI as "built for both
  humans and AI agents"
- Subsections: claim flow (`mem0 init --email`), plugin sync behavior
  (`~/.claude/settings.json` + shell rc)
- `mem0 init` flag table extended with --agent, --agent-caller, --source
- New `mem0 identify` subcommand reference (PATCHes the active key's
  agent_caller)

All angle-bracket placeholders inside backticks (e.g. `<your-name>`,
`<memory-id>`) — verified no naked <... JSX traps remain that would
break Mintlify parsing.
2026-05-14 21:27:13 +05:30
Mgeeeek 95a8da31eb fix(docs): escape <5s in CLI v0.2.5 changelog — Mintlify MDX parse error
Mintlify deployment failed after #5123 merged because docs/changelog/sdk.mdx
contained naked `<5s` text. MDX treats `<` as a JSX tag opener, but `5` is
not a valid identifier-start character, so the parser errors:

  "Failed to parse page content at path changelog/sdk.mdx: Unexpected
   character `5` (U+0035) before name, expected a character that can
   start a name, such as a letter, `$`, or `_`"

Replace `in <5s` with `in under 5 seconds`. Other `<...>` patterns in the
entry (e.g. `<name>`, `<email>`, `<their-email>`) are all inside backticks
which Mintlify treats as literal code spans, so they don't trigger the
JSX parser.
2026-05-14 21:23:21 +05:30
10 changed files with 145 additions and 57 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
"name": "mem0", "name": "mem0",
"source": "./mem0-plugin", "source": "./mem0-plugin",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.", "description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
"version": "0.1.3" "version": "0.1.2"
} }
] ]
} }
+1 -1
View File
@@ -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"> <Update label="2026-05-14" description="Python v0.2.5 / Node v0.2.5">
**New Features:** **New Features:**
- **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)) - **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))
- **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)) - **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)) - **`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)) - **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))
+55 -2
View File
@@ -25,7 +25,44 @@ pip install mem0-cli
``` ```
</CodeGroup> </CodeGroup>
## Authentication ## 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)
Run the interactive setup wizard to configure your API key: Run the interactive setup wizard to configure your API key:
@@ -79,6 +116,7 @@ Interactive setup wizard. Prompts for your API key and default user ID.
mem0 init mem0 init
mem0 init --api-key m0-xxx --user-id alice mem0 init --api-key m0-xxx --user-id alice
mem0 init --email alice@company.com 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). 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).
@@ -91,10 +129,25 @@ mem0 init --api-key m0-xxx --user-id alice --force
|------|-------------| |------|-------------|
| `--api-key` | API key (skip prompt) | | `--api-key` | API key (skip prompt) |
| `-u, --user-id` | Default user ID (skip prompt) | | `-u, --user-id` | Default user ID (skip prompt) |
| `--email` | Login via email verification code | | `--email` | Login via email verification code (also used to claim an Agent Mode key) |
| `--code` | Verification code (use with `--email` for non-interactive login) | | `--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 | | `--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` ### `mem0 add`
Add a memory from text, a JSON messages array, a file, or stdin. Add a memory from text, a JSON messages array, a file, or stdin.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "mem0", "name": "mem0",
"version": "0.1.3", "version": "0.1.2",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows using the Mem0 Platform MCP server.", "description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows using the Mem0 Platform MCP server.",
"author": { "author": {
"name": "Mem0", "name": "Mem0",
-45
View File
@@ -1,45 +0,0 @@
# 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`).
+44 -2
View File
@@ -1,17 +1,59 @@
"""Resolve mem0 user_id. """Resolve mem0 user_id with deterministic priority.
Resolution priority: Resolution priority:
1. MEM0_USER_ID env var (explicit override) 1. MEM0_USER_ID env var (explicit override)
2. $USER, else "default" 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.
""" """
from __future__ import annotations from __future__ import annotations
import hashlib
import json
import os import os
from datetime import datetime, timezone
_CACHE_PATH = os.path.expanduser("~/.mem0/identity.json")
def resolve_user_id() -> str: def resolve_user_id() -> str:
explicit = os.environ.get("MEM0_USER_ID", "").strip() explicit = os.environ.get("MEM0_USER_ID", "").strip()
if explicit: if explicit:
return 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" return os.environ.get("USER") or "default"
+42 -1
View File
@@ -2,13 +2,54 @@
# #
# Resolution priority: # Resolution priority:
# 1. MEM0_USER_ID env var (explicit override) # 1. MEM0_USER_ID env var (explicit override)
# 2. $USER, else "default" # 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
}
_mem0_resolve_identity() { _mem0_resolve_identity() {
if [ -n "${MEM0_USER_ID:-}" ]; then if [ -n "${MEM0_USER_ID:-}" ]; then
printf '%s' "$MEM0_USER_ID" printf '%s' "$MEM0_USER_ID"
return return
fi 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}" printf '%s' "${USER:-default}"
} }
+1 -1
View File
@@ -36,7 +36,7 @@ echo "## Mem0 Identity"
echo "" echo ""
echo "Active user_id: \`$MEM0_RESOLVED_USER_ID\`" echo "Active user_id: \`$MEM0_RESOLVED_USER_ID\`"
echo "" 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 the agent's MCP calls aligned with the bucket the hooks write to." 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 "" echo ""
if [ "$SOURCE" = "startup" ]; then if [ "$SOURCE" = "startup" ]; then
-2
View File
@@ -4,5 +4,3 @@ __version__ = importlib.metadata.version("mem0ai")
from mem0.client.main import AsyncMemoryClient, MemoryClient # noqa from mem0.client.main import AsyncMemoryClient, MemoryClient # noqa
from mem0.memory.main import AsyncMemory, Memory # noqa from mem0.memory.main import AsyncMemory, Memory # noqa
-1
View File
@@ -156,4 +156,3 @@ known_first_party = ["mem0", "mem0_cli"]
# isort scope kept aligned with [tool.ruff.lint.isort] above. # isort scope kept aligned with [tool.ruff.lint.isort] above.
# black-equivalent profile here matches the formatter behaviour ruff applies. # 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). # Plugin-version bumps need a touch here to fire required CI checks (path-filter trap).
# Last touched: plugin v0.1.3