From 6a1597c6fba44a0ed516c06028120c69df2ba7e9 Mon Sep 17 00:00:00 2001 From: Mragank Shekhar Date: Fri, 15 May 2026 02:37:55 +0530 Subject: [PATCH] fix(plugin): drop API-key-derived user_id, restore $USER fallback (#5147) --- .claude-plugin/marketplace.json | 2 +- mem0-plugin/.claude-plugin/plugin.json | 2 +- mem0-plugin/CHANGELOG.md | 45 ++++++++++++++++++++++++ mem0-plugin/scripts/_identity.py | 46 ++----------------------- mem0-plugin/scripts/_identity.sh | 43 +---------------------- mem0-plugin/scripts/on_session_start.sh | 2 +- pyproject.toml | 1 + 7 files changed, 52 insertions(+), 89 deletions(-) create mode 100644 mem0-plugin/CHANGELOG.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 3bf63cfbd..fe31f6412 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -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" } ] } diff --git a/mem0-plugin/.claude-plugin/plugin.json b/mem0-plugin/.claude-plugin/plugin.json index 0eb499f98..a91dd5d30 100644 --- a/mem0-plugin/.claude-plugin/plugin.json +++ b/mem0-plugin/.claude-plugin/plugin.json @@ -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", diff --git a/mem0-plugin/CHANGELOG.md b/mem0-plugin/CHANGELOG.md new file mode 100644 index 000000000..6690a1b14 --- /dev/null +++ b/mem0-plugin/CHANGELOG.md @@ -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-`. To recover: temporarily `export MEM0_USER_ID=mem0-`, 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`). diff --git a/mem0-plugin/scripts/_identity.py b/mem0-plugin/scripts/_identity.py index 0725be58e..a80f4e058 100644 --- a/mem0-plugin/scripts/_identity.py +++ b/mem0-plugin/scripts/_identity.py @@ -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" diff --git a/mem0-plugin/scripts/_identity.sh b/mem0-plugin/scripts/_identity.sh index 3e0b62a17..cf4ae756c 100644 --- a/mem0-plugin/scripts/_identity.sh +++ b/mem0-plugin/scripts/_identity.sh @@ -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}" } diff --git a/mem0-plugin/scripts/on_session_start.sh b/mem0-plugin/scripts/on_session_start.sh index cd31eb39a..f47b42e1c 100755 --- a/mem0-plugin/scripts/on_session_start.sh +++ b/mem0-plugin/scripts/on_session_start.sh @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 998a81890..de3f48d55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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