Compare commits

..

18 Commits

Author SHA1 Message Date
Mgeeeek 6158ac1065 chore: trigger CI build_mem0 / build_embedchain on cli-only PR 2026-05-14 19:56:56 +05:30
Mgeeeek 3d3303bf36 chore(cli): bump to v0.2.5 + changelog + ruff format fix
- Python: 0.2.4 → 0.2.5 in cli/python/pyproject.toml
- Node:   0.2.4 → 0.2.5 in cli/node/package.json
- docs/changelog/sdk.mdx: new CLI v0.2.5 entry (Agent Mode bootstrap,
  --agent-caller, mem0 identify, plugin sync, claim flow, pingKey fix,
  rate-limit clarity, JSON envelope command field, envelope validation)
- CI fix: ruff format applied to config.py + test_init_internals.py

Release flow: merge → tag cli-v0.2.5 (Python CD) and cli-node-v0.2.5
(Node CD) on GitHub Releases. OIDC trusted publishing — no tokens needed.
2026-05-14 19:51:27 +05:30
Mgeeeek bd6d170ebb fix(cli): pingKey distinguishes network failures from invalid keys + tests
PR review surfaced a data-loss path: pingKey returned False on ANY exception,
so a VPN flap or DNS hiccup made Rules 1/2 (reuse existing valid key) fall
through to Rule 3 (mint new shadow), silently rotating the user's API key
and rewriting plugin-sync targets (~/.claude/settings.json, .zshrc).

Now pingKey returns False ONLY on a definitive auth failure (HTTP 401/403).
Network errors, timeouts, and 5xx responses return True so the existing key
is preferred over re-minting. Mirror change in both Python and Node.

Additional fixes from the same review pass:

  - --agent-caller is now PATCHed to the backend when supplied on a Rule 1
    or Rule 2 reuse path (previously silently dropped). Best-effort —
    failures don't break reuse.

  - bootstrap_via_backend / bootstrapViaBackend renames the `body` local on
    the error path to `err_body` (no longer shadows the request payload).
    Same rename in the claim flow.

  - Bootstrap envelope is now validated for non-empty api_key +
    default_user_id before mutation — defends against partial backend
    responses silently persisting null/undefined into typed string fields.

  - Stale docstrings in agent_detect.{py,ts} and bootstrap_via_backend no
    longer claim env-var sniffing fills `agent_caller`; the field is
    self-declared via --agent-caller only.

Tests (new file mirrored across runtimes):

  - test_init_internals.py / init-internals.test.ts
  - pingKey: 200/401/403/5xx/connect-error/timeout matrix
  - plugin_sync.updateShellRc: trailing-newline preservation, no-create,
    surrounding-content preservation, idempotency, missing-file no-op
  - plugin_sync.updateClaudeSettings: no env-block creation, no
    MEM0_API_KEY insertion into existing env, idempotency, malformed JSON
    no-op
  - Python only: bootstrap 403 "permission" → daily-limit translation

Python: 161 tests pass. Node: 112 tests pass. ruff + biome clean.
2026-05-14 19:39:05 +05:30
Mgeeeek a5cdd45651 docs: teach agents the --agent-caller flag + mem0 identify fallback
Update all Agent Mode quickstart references so agents know how to
attribute their signup:

  1. Canonical: mem0 init --agent --agent-caller <your-name> --json
  2. Fallback if forgotten: mem0 identify <your-name>

Files updated:
- README.md: Agent Mode promo line
- docs/llms.txt: LLM-facing quickstart
- skills/mem0-cli/SKILL.md: Autonomous setup section
- skills/mem0-cli/references/command-reference.md: --agent / --agent-caller / --source columns added to init; new `mem0 identify` section
- skills/mem0/SKILL.md: setup-without-key fallback
- skills/mem0-integrate/SKILL.md: Platform-track key-missing branch

Backend changes that this docs change pairs with: mem0ai/platform#2784
(open sanitize-only normalize + PATCH /agent_mode/caller/).
2026-05-14 18:00:08 +05:30
Mgeeeek a9455313cc feat(cli): mem0 identify <name> — post-init agent self-identify
Adds a one-shot subcommand the agent runs when it bootstrapped without
--agent-caller: `mem0 identify claude-code` PATCHes the active key's
agent_caller via /api/v1/auth/agent_mode/caller/, then mirrors the
canonical value into ~/.mem0/config.json.

Bootstrap success message now prompts unidentified agents to run it.
If --agent-caller was passed on init, no prompt (already attributed).

Both runtimes (Python + Node) get the command + the prompt update.
2026-05-14 17:57:35 +05:30
Mgeeeek 8aa07c2f62 refactor(cli): self-declared agent_caller via --agent-caller flag
Switch agent identity from env-var sniffing to explicit self-declaration
(Proof Editor-style). The agent now passes its own name when running
mem0 init --agent --agent-caller <name>.

Why: env-var detection was speculative for everything but Claude Code —
CLAUDECODE=1 is documented and verified, but CURSOR_AGENT, CODEX_CLI,
CLINE_AGENT etc. were plausible-sounding picks without upstream
confirmation. Self-declaration is honest, future-proof (no whitelist
treadmill as new agents emerge), and matches how Proof handles agent
join: explicit identity from the agent itself.

CLI changes:
- New --agent-caller <name> option on `mem0 init` (Python + Node)
- Removed detect_agent_caller() as the source for agent_caller field;
  still used as a context trigger ("does this look like an agent?")
  for Rule 3 auto-bootstrap and for telemetry-only event property —
  identity goes to NULL unless --agent-caller is passed
- runInit / run_init accept agent_caller kwarg, forward to backend
- PostHog cli.init event uses the self-declared value (not env-sniffed)

Companion backend change (mem0ai/platform#2784) drops the whitelist
normalizer for an open sanitize so any sensible name is accepted.
2026-05-14 17:40:52 +05:30
Mgeeeek d54dad265d feat(cli): pass detected agent_caller to backend on Agent Mode bootstrap
The CLI's detect_agent_caller() already canonicalizes the caller (env-var
sniff returning "claude-code", "cursor", etc.) and reports it to PostHog —
but the value never reached the backend, so APIKey.agent_caller stayed
NULL. Join: send it in the bootstrap request body so the platform can
persist it (see mem0ai/platform#2784).

Wire-up:
- bootstrap_via_backend / bootstrapViaBackend gain an agent_caller kwarg,
  pass it as request body field "agent_caller"
- init_cmd / init.ts call detect_agent_caller() once and forward
- platform.agent_caller persisted to ~/.mem0/config.json so the local
  view matches what the backend stored

No change to created_via — that stays the channel enum ("agent_mode" /
"email" / "api_key"). agent_caller is the orthogonal "who started this".
2026-05-14 17:24:12 +05:30
Mgeeeek bac961bc8d style(cli): biome format multi-line import in node index.ts 2026-05-14 17:01:14 +05:30
Mgeeeek f21e9fe2b3 fix(cli): JSON error envelope shows command name + clearer rate-limit message
Two papercuts surfaced when prod's bootstrap returned 403:

  {"status": "error", "command": "", "error": "Bootstrap failed: {\"detail\":\"You do not have permission to perform this action.\"}", "data": null}

1. `"command": ""` — the JSON error envelope (printError under agent
   mode) reads from current_command state, but nothing ever called
   setCurrentCommand on the init subcommand. Hook into Node's
   preAction and Python's main_callback to stash the active
   subcommand name so error envelopes report which command failed.

2. Opaque rate-limit message. The backend's @ratelimit decorator
   raises PermissionDenied → DRF translates to generic 403
   "You do not have permission to perform this action." Users don't
   know it's a rate limit. Detect status_code==403 with /permission/i
   in the detail and surface the actual reason:
   "Daily Agent Mode signup limit reached for this network (5/day).
   Try again from a different IP or after midnight UTC."

Both fixes mirrored in Python (agent_mode_cmd.py, app.py) and Node
(agent-mode.ts, index.ts).
2026-05-14 16:43:17 +05:30
Mgeeeek 844d633960 feat(cli): emit JSON envelope on init --agent --json reuse paths
PRD's documented form is `mem0 init --agent --json`, but rules 1/2
(env/config reuse) called printSuccess which is silenced under
agent mode — so the command exited 0 with no output.

Two related fixes:

1. Add `--json` as a subcommand-level option on init (Node only;
   Python's argv preprocessor already handles this). Lets the
   PRD-style invocation `mem0 init --agent --json` parse without
   "unknown option" error.

2. When agent mode is set AND a rule 1/2 reuse fires, emit the
   Dev Spec C4 envelope:
     {
       "status": "success", "command": "init",
       "data": {
         "api_key_saved": false,
         "api_key_source": "env" | "config",
         "agent_mode": false,
         "message": "Existing Mem0 API key found and reused..."
       }
     }
   Identical shape between Python and Node (parity).

Verified live: `init --agent --json` against prod with a valid
MEM0_API_KEY env returns the envelope above (no bootstrap call).
2026-05-14 16:30:52 +05:30
Mgeeeek 4f40437d65 feat(cli): auto-sync active api_key to plugin env touchpoints
When saveConfig writes a fresh api_key (e.g. agent-mode bootstrap, OTP
signup), propagate the value into other ecosystem locations that hold
the same key:

  - ~/.claude/settings.json::env::MEM0_API_KEY (Claude Code env injection)
  - ~/.zshrc / ~/.bashrc / ~/.bash_profile `export MEM0_API_KEY="..."`

Without this, agent-mode bootstrap mints a new shadow into config.json
but the Claude plugin's MCP server keeps using the OLD env-var key —
silent surprise.

Hard guarantees:

  1. **Update-only**, never create. If a target file doesn't already
     contain a MEM0_API_KEY entry, we leave it alone. The user's
     existing setup decides which surfaces are managed; we don't
     unilaterally start writing to new files.
  2. **Preserve surrounding content.** JSON files keep all other keys.
     Shell rc files keep all other lines, comments, and the trailing
     newline (regex uses [ \t]* not \s*, which would eat the final \n
     when MEM0_API_KEY is the last line of .zshrc).
  3. **Atomic writes.** tmpfile + rename, so a crash mid-write leaves
     the original intact.
  4. **Idempotent.** If the target already has this value, no-op.
  5. **Best-effort.** Any IOError in the sync is swallowed; the
     canonical config.json write is never blocked by plugin-state.

Implemented identically in Python (plugin_sync.py) and Node
(plugin-sync.ts). Hooked into save_config() / saveConfig() so every
api_key change propagates without any caller plumbing.

Verified on a sandbox copy of real ~/.claude/settings.json and
~/.zshrc: only the MEM0_API_KEY values changed; all 36 other lines
in settings.json and 50+ lines in .zshrc preserved byte-for-byte
including the trailing newline.

Out of scope (deliberate non-changes):
  - ~/.codex/config.toml — no mem0 server entry to update
  - ~/.cursor/mcp.json — no mem0 server entry to update
  - <plugin-install-dir>/.api_key — plugin-managed, different schema
2026-05-14 16:19:21 +05:30
Mgeeeek 477279daeb feat(cli): implement Dev Spec C4 rules 1-2 — reuse valid env/config key
Before this change, `mem0 init --agent` always minted a fresh shadow,
even when a valid MEM0_API_KEY env var (set by the Claude plugin or
shell rc) was already in place. The env var would then silently shadow
the freshly-minted shadow key on the next CLI call — leading to the
surprising "Agent Mode active but my personal account does the work"
behaviour.

Dev Spec §C4 already specifies the right precedence:
  Rule 1: env MEM0_API_KEY valid → reuse, emit existing_key, no new key
  Rule 2: config api_key valid → reuse, emit existing_key
  Rule 3: mint a fresh shadow

This commit implements rules 1-3 in both runtimes (Python + Node), with
a 5-second ping to validate candidate keys against /v1/ping/.

Also reorders so the Agent Mode branch runs BEFORE the existing-config
overwrite guard. The guard's intent is "warn before overwriting a valid
key" — but rules 1/2 REUSE (not overwrite) a valid key, so the guard
must not fire on the agent path.

Net effect: the plugin's MEM0_API_KEY env var and the CLI's
config.json::platform.api_key now naturally co-exist:

  - User installs plugin → MEM0_API_KEY set, persisted via shell rc
  - User runs `mem0 init --agent` → rule 1 fires → existing key kept,
    no shadow created, no confusion
  - Plugin's MCP server (which reads ${MEM0_API_KEY}) and the CLI use
    the same key

No new shadow accounts on prod from CI / repeat invocations.
2026-05-14 16:10:31 +05:30
Mgeeeek 37d5658171 fix(cli): mem0 init --agent now triggers bootstrap (Node) + created_via parity
External sandbox audit (Sandbox E2E Test Report 2026-05-13) surfaced
two CLI issues.

1. Node — `mem0 init --agent` silently falls through to the non-TTY
   error when no agent env var is set. Commander resolves the
   program-level `--agent` alias (for --json) before init's own
   `--agent`; init's opts.agent stays false. Fix: enable Commander's
   positional options so flags AFTER a subcommand belong to that
   subcommand. Now `mem0 --agent <cmd>` is the JSON-output alias and
   `mem0 init --agent` is the Agent Mode bootstrap flag.

   The Python side already had an argv preprocessor doing the
   equivalent; this brings Node to parity using Commander's built-in
   mechanism (cleaner than mirroring the preprocessor).

   Verified: `mem0 init --agent` with bogus MEM0_BASE_URL now hits the
   bootstrap fetch and surfaces a network error (proving it reached
   bootstrap_via_backend), where before it printed "Non-interactive
   terminal detected" and never made an HTTP call.

2. Both — `config.platform.created_via` was inconsistent: set to
   "agent_mode" / "email" on the agent/claim paths but left empty on
   normal email signup and api-key paths. Now all four paths set it:
   "agent_mode" (bootstrap), "email" (OTP signup or claim), "api_key"
   (--api-key flag or interactive prompt). Downstream consumers can
   reliably filter on created_via==value.
2026-05-14 14:48:01 +05:30
Mgeeeek 0414aedce5 fix(cli): escape user-supplied message in print_error
Backend error details can contain `[/...]` or other rich-markup-like text
(e.g. regex patterns in validation errors). print_error interpolated the
raw string into a markup template, so rich's parser would crash with
MarkupError instead of showing the actual error to the user.

Escape message + hint via rich.markup.escape so the colored prefix
still renders but the user-supplied content prints literally.
2026-05-14 04:03:35 +05:30
Mgeeeek a2516269cc Surface mem0_notice for unclaimed Agent Mode keys + docs
CLI now consumes the unified mem0_notice surface that the platform side
emits for unclaimed Agent Mode keys. The notice is a directive to the
LLM agent reading the output, with a verbatim sentence to relay to the
human owner. Two presentation paths:

- Human/text output: yellow stderr banner after the primary output,
  once per command. Skipped in agent mode (the JSON envelope carries
  it instead, so no duplication).
- JSON/agent output (--json/--agent): folded into the envelope as
  "mem0_notice" so an agent parsing the output sees it without
  inspecting HTTP headers.

CLI changes (Python + Node, kept in lockstep):
- state.{ts,py}: captureNotice / takeNotice helpers — last-write-wins
  stash so multi-request commands fire the notice exactly once.
- backend/platform.{ts,py}: _request extracts notice from response
  bodies (top-level dict or list[0]) with header fallback, strips
  from downstream payload, captures for end-of-command surfacing.
- output.{ts,py}: JSON envelope formatters fold in any pending notice.
- index.ts / app.py: entrypoint surfaces notice on exit when not in
  agent mode.
- commands/agent-mode.{ts,py}: init success path prints the platform's
  notice verbatim (fallback to dim claim-command line if a stale
  backend doesn't return it).

Init-flag handling fix: the Python argv preprocessor was stripping
--agent from sys.argv unconditionally as the global JSON-output alias.
That swallowed `mem0 init --agent` (where --agent is a subcommand flag
for unattended bootstrap). Now preserved when "init" is in argv.

Parity tests: cli/python/tests/test_agent_mode.py and
cli/node/tests/agent-mode.test.ts — 7 tests each, kept in sync.

cli-spec.json updated: init now lists --agent and --source.

Docs:
- README.md: Agent Mode promo at top of Quickstart.
- docs/llms.txt: fast-path block for AI agents reading the docs.
- skills/mem0/SKILL.md, skills/mem0-cli/SKILL.md,
  skills/mem0-integrate/SKILL.md, mem0-plugin/skills/mem0/SKILL.md:
  autonomous-setup section + fallback hints.
- mem0-plugin/README.md, openclaw/README.md: "Quick path for agents"
  blocks above the human Quick Start.
2026-05-14 02:11:39 +05:30
Mgeeeek 1c92c466c4 feat(cli): rework claim to OTP-only — drop device flow + browser + polling
Replace claim_via_device_flow / claimViaDeviceFlow with claim_via_otp /
claimViaOtp. The new flow:
  1. POST /api/v1/auth/email_code/ with the user's email
  2. Prompt for the verification code (or accept via --code for non-TTY)
  3. POST /.../verify/ with {email, code, agent_mode_api_key: <local key>}
  4. Backend's verify_email_code runs upgrade-in-place inline and returns
     {claimed: true, claimed_at, ...}

No browser open, no localhost:3000 frontend dependency, no 10-minute poll
loop. Just two HTTP calls + an OTP prompt. Same upgrade-in-place
semantics on the backend; same key-value-unchanged guarantee for the
caller.

--code flag still supported on `mem0 init --email` for non-interactive
use (CI, agent-driven claim scripts).
2026-05-13 23:08:20 +05:30
Mgeeeek bcba0560c4 feat(cli): Agent Mode bootstrap + claim flow (Node)
Mirrors the Python implementation in TypeScript:
  - New PlatformConfig fields: agentMode, createdVia, claimedAt, defaultUserId.
  - agent-detect.ts: detectAgentCaller() — env-var detection covering
    CLAUDECODE / CURSOR_AGENT / CODEX_CLI / CLINE / CONTINUE / AIDER /
    GOOSE / WINDSURF.
  - commands/agent-mode.ts: bootstrapViaBackend() + claimViaDeviceFlow().
  - commands/init.ts: decision tree dispatches to bootstrap (positive agent
    signal + no email/api-key) or claim (--email with existing agent-mode
    config). Raw API key never leaves the device through the claim.
  - index.ts: --agent and --source flags added to `mem0 init`. Skip the
    preAction auto-fire for init so it can fire its own M1-M6 cli.init.
  - telemetry.ts: all cli.* events now carry agent_mode based on
    config.platform.agentMode (per growth-doc M4).

End-to-end verified against the sandbox:
  bootstrap (CLAUDECODE=1) → config.agent_mode=true → claim via --email →
  config.agent_mode=false, claimed_at set, api_key unchanged.
2026-05-13 23:08:20 +05:30
Mgeeeek 84ffb36190 feat(cli): Agent Mode bootstrap + claim flow (Python)
New behavior on `mem0 init`:
  - With no `--email`/`--api-key` AND a positive agent signal (`--agent`,
    global `--json`/`--agent`, or one of the recognized agent env vars
    CLAUDECODE / CURSOR_AGENT / CODEX_CLI / CLINE / CONTINUE / AIDER /
    GOOSE / WINDSURF), bootstrap an unattended Agent Mode account via
    POST /api/v1/auth/agent_mode/. No email, no OTP, no dashboard.
  - With `--email <addr>` AND an existing config that has agent_mode=true,
    run the claim device-flow against the existing key instead of minting
    a fresh one. The raw API key never leaves the device; backend confirms
    claim via the existing CLILoginRequest poll path. Config flips
    agent_mode=false and stamps claimed_at on success.
  - Bare `mem0 init` with no signal + no TTY still errors out — auto-bootstrap
    requires a positive agent signal to avoid surprising pipe-using humans.

New flags:
  --agent   Force unattended Agent Mode bootstrap.
  --source  Channel attribution string for signup_source PostHog property.

Config schema extensions on PlatformConfig:
  agent_mode, created_via, claimed_at, default_user_id.

Telemetry (M1-M6 from the growth doc):
  - cli.init: mode (agent|email|api_key|existing_key), agent_caller,
    signup_source, claimed_agent_mode (bool when --email claims an
    existing agent-mode config).
  - All cli.* events: agent_mode reflects config.platform.agent_mode (the
    bootstrap flag), not the output-format flag — per the growth-doc spec.
2026-05-13 23:08:20 +05:30
1141 changed files with 59589 additions and 50936 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
"name": "mem0",
"source": {
"source": "local",
"path": "./integrations/mem0-plugin"
"path": "./mem0-plugin"
},
"policy": {
"installation": "AVAILABLE",
+2 -2
View File
@@ -10,9 +10,9 @@
"plugins": [
{
"name": "mem0",
"source": "./integrations/mem0-plugin",
"source": "./mem0-plugin",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
"version": "0.2.10"
"version": "0.1.2"
}
]
}
-20
View File
@@ -1,20 +0,0 @@
{
"name": "mem0-plugins",
"interface": {
"displayName": "Mem0 Plugins"
},
"plugins": [
{
"name": "mem0",
"source": {
"source": "local",
"path": "./integrations/mem0-plugin"
},
"policy": {
"installation": "AVAILABLE",
"authentication": "ON_INSTALL"
},
"category": "Productivity"
}
]
}
+2 -2
View File
@@ -10,9 +10,9 @@
"plugins": [
{
"name": "mem0",
"source": "./integrations/mem0-plugin",
"source": "./mem0-plugin",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search.",
"version": "0.2.10"
"version": "0.1.1"
}
]
}
+4 -18
View File
@@ -1,33 +1,18 @@
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
# Dispatched by release.yml (Release Router) when a release tagged v* is
# published. Can also be dispatched manually to re-publish a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. v1.2.3)'
required: true
type: string
prerelease:
description: 'Unused for PyPI (pre-releases are expressed in the version itself); accepted for router uniformity'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
# Pure SDK version tags only (v1.2.3) — excludes package-prefixed tags
# like vercel-ai-v* that also start with 'v'
if: startsWith(inputs.tag, 'v') && !contains(inputs.tag, '-v')
if: startsWith(github.event.release.tag_name, 'v')
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/checkout@v2
with:
ref: ${{ inputs.tag }}
- name: Set up Python
uses: actions/setup-python@v2
@@ -54,6 +39,7 @@ jobs:
# packages_dir: dist/
- name: Publish distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/v')
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages_dir: dist/
-171
View File
@@ -1,171 +0,0 @@
name: CI Gate
# Single required status check for all PRs.
#
# Path-filtered CI workflows can't be marked as required in branch
# protection: on a PR that doesn't touch their paths they never report, and
# the required check hangs at "Expected" forever. This gate solves that. It
# runs on every PR, detects which packages changed, calls only the relevant
# package CI workflows (as reusable workflows), and the final "CI Gate" job
# reports the aggregate result — success when every invoked pipeline passed
# (skipped pipelines are fine), failure when any failed.
#
# Branch protection should require exactly one status check: "CI Gate".
#
# Package CI workflows keep their own push-to-main and workflow_dispatch
# triggers; only their pull_request triggers moved here. To wire in a new
# package: add a filter under the `changes` job, a call job that `uses:` the
# package workflow, and list the call job in the gate's `needs`.
on:
pull_request:
concurrency:
group: ci-gate-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read
jobs:
changes:
name: Detect changed packages
runs-on: ubuntu-latest
outputs:
python_sdk: ${{ steps.filter.outputs.python_sdk }}
ts_sdk: ${{ steps.filter.outputs.ts_sdk }}
cli_python: ${{ steps.filter.outputs.cli_python }}
cli_node: ${{ steps.filter.outputs.cli_node }}
openclaw: ${{ steps.filter.outputs.openclaw }}
opencode_plugin: ${{ steps.filter.outputs.opencode_plugin }}
pi_agent_plugin: ${{ steps.filter.outputs.pi_agent_plugin }}
docs_llms_txt: ${{ steps.filter.outputs.docs_llms_txt }}
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
# Each filter mirrors the package workflow's old pull_request
# paths, plus the package workflow file itself and this gate file
# (changing either must re-exercise the pipeline).
filters: |
python_sdk:
- 'mem0/**'
- 'tests/**'
- 'pyproject.toml'
- '.github/workflows/ci.yml'
- '.github/workflows/ci-gate.yml'
ts_sdk:
- 'mem0-ts/**'
- '.github/workflows/ts-sdk-ci.yml'
- '.github/workflows/ci-gate.yml'
cli_python:
- 'cli/python/**'
- '.github/workflows/cli-python-ci.yml'
- '.github/workflows/ci-gate.yml'
cli_node:
- 'cli/node/**'
- '.github/workflows/cli-node-ci.yml'
- '.github/workflows/ci-gate.yml'
openclaw:
- 'integrations/openclaw/**'
- '.github/workflows/openclaw-checks.yml'
- '.github/workflows/ci-gate.yml'
opencode_plugin:
- 'integrations/mem0-plugin/.opencode-plugin/**'
- '.github/workflows/opencode-plugin-checks.yml'
- '.github/workflows/ci-gate.yml'
pi_agent_plugin:
- 'integrations/pi-agent-plugin/**'
- '.github/workflows/pi-agent-plugin-checks.yml'
- '.github/workflows/ci-gate.yml'
docs_llms_txt:
- 'docs/**/*.mdx'
- 'docs/llms.txt'
- 'scripts/check-llms-txt-coverage.py'
- 'scripts/llms-txt-ignore.txt'
- '.github/workflows/docs-llms-txt-check.yml'
- '.github/workflows/ci-gate.yml'
python-sdk:
name: Python SDK
needs: changes
if: needs.changes.outputs.python_sdk == 'true'
uses: ./.github/workflows/ci.yml
secrets: inherit
ts-sdk:
name: TypeScript SDK
needs: changes
if: needs.changes.outputs.ts_sdk == 'true'
uses: ./.github/workflows/ts-sdk-ci.yml
secrets: inherit
cli-python:
name: Python CLI
needs: changes
if: needs.changes.outputs.cli_python == 'true'
uses: ./.github/workflows/cli-python-ci.yml
secrets: inherit
cli-node:
name: Node CLI
needs: changes
if: needs.changes.outputs.cli_node == 'true'
uses: ./.github/workflows/cli-node-ci.yml
secrets: inherit
openclaw:
name: OpenClaw
needs: changes
if: needs.changes.outputs.openclaw == 'true'
uses: ./.github/workflows/openclaw-checks.yml
secrets: inherit
opencode-plugin:
name: OpenCode Plugin
needs: changes
if: needs.changes.outputs.opencode_plugin == 'true'
uses: ./.github/workflows/opencode-plugin-checks.yml
secrets: inherit
pi-agent-plugin:
name: Pi Agent Plugin
needs: changes
if: needs.changes.outputs.pi_agent_plugin == 'true'
uses: ./.github/workflows/pi-agent-plugin-checks.yml
secrets: inherit
docs-llms-txt:
name: docs llms.txt
needs: changes
if: needs.changes.outputs.docs_llms_txt == 'true'
uses: ./.github/workflows/docs-llms-txt-check.yml
secrets: inherit
gate:
name: CI Gate
needs:
- changes
- python-sdk
- ts-sdk
- cli-python
- cli-node
- openclaw
- opencode-plugin
- pi-agent-plugin
- docs-llms-txt
if: always()
runs-on: ubuntu-latest
steps:
- name: Evaluate pipeline results
env:
NEEDS: ${{ toJSON(needs) }}
run: |
echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
failed=$(echo "$NEEDS" | jq -r '[to_entries[] | select(.value.result == "failure" or .value.result == "cancelled") | .key] | join(", ")')
if [ -n "$failed" ]; then
echo "::error::Failing pipelines: $failed"
exit 1
fi
echo "All pipelines relevant to this change passed."
+59 -18
View File
@@ -1,11 +1,20 @@
name: ci
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main runs remain standalone.
on:
push:
branches: [main]
workflow_call:
paths:
- 'mem0/**'
- 'tests/**'
- 'embedchain/**'
- '.github/workflows/**'
- 'pyproject.toml'
pull_request:
paths:
- 'mem0/**'
- 'tests/**'
- 'embedchain/**'
- 'pyproject.toml'
jobs:
changelog_check:
@@ -51,8 +60,9 @@ jobs:
runs-on: ubuntu-latest
outputs:
mem0_changed: ${{ steps.filter.outputs.mem0 }}
embedchain_changed: ${{ steps.filter.outputs.embedchain }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
@@ -60,28 +70,25 @@ jobs:
mem0:
- 'mem0/**'
- 'tests/**'
- '.github/workflows/ci.yml'
- '.github/workflows/**'
- 'pyproject.toml'
embedchain:
- 'embedchain/**'
build_mem0:
needs: check_changes
if: needs.check_changes.outputs.mem0_changed == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- name: Skip — no relevant changes
if: needs.check_changes.outputs.mem0_changed != 'true'
run: echo "No changes in mem0/, tests/, pyproject.toml, or ci.yml — skipping"
- uses: actions/checkout@v4
if: needs.check_changes.outputs.mem0_changed == 'true'
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
if: needs.check_changes.outputs.mem0_changed == 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Clean up disk space
if: needs.check_changes.outputs.mem0_changed == 'true'
run: |
df -h
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
@@ -89,27 +96,61 @@ jobs:
sudo docker builder prune -a
df -h
- name: Install Hatch
if: needs.check_changes.outputs.mem0_changed == 'true'
run: pip install hatch
- name: Load cached venv
if: needs.check_changes.outputs.mem0_changed == 'true'
id: cached-hatch-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-mem0-${{ runner.os }}-${{ hashFiles('**/pyproject.toml') }}
- name: Install GEOS Libraries
if: needs.check_changes.outputs.mem0_changed == 'true'
run: sudo apt-get update && sudo apt-get install -y libgeos-dev
- name: Install dependencies
if: needs.check_changes.outputs.mem0_changed == 'true' && steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
run: |
pip install --upgrade pip
pip install -e ".[test,graph,vector_stores,llms,extras]"
pip install ruff
if: steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
- name: Run Linting
if: needs.check_changes.outputs.mem0_changed == 'true'
run: make lint
- name: Run tests and generate coverage report
if: needs.check_changes.outputs.mem0_changed == 'true'
run: make test
build_embedchain:
needs: check_changes
if: needs.check_changes.outputs.embedchain_changed == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Hatch
run: pip install hatch
- name: Load cached venv
id: cached-hatch-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-embedchain-${{ runner.os }}-${{ hashFiles('**/pyproject.toml') }}
- name: Install dependencies
run: cd embedchain && make install_all
if: steps.cached-hatch-dependencies.outputs.cache-hit != 'true'
- name: Run Formatting
run: |
mkdir -p embedchain/.ruff_cache && chmod -R 777 embedchain/.ruff_cache
cd embedchain && hatch run format
- name: Lint with ruff
run: cd embedchain && make lint
- name: Run tests and generate coverage report
run: cd embedchain && make coverage
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
with:
file: coverage.xml
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+4 -18
View File
@@ -1,25 +1,13 @@
name: Publish @mem0/cli 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged
# cli-node-v* is published. Can also be dispatched manually to re-publish
# a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. cli-node-v0.2.0)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish @mem0/cli 📦 to npm
if: startsWith(inputs.tag, 'cli-node-v')
if: startsWith(github.event.release.tag_name, 'cli-node-v')
runs-on: ubuntu-latest
permissions:
id-token: write
@@ -28,8 +16,6 @@ jobs:
working-directory: cli/node
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -52,7 +38,7 @@ jobs:
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
+4 -3
View File
@@ -1,7 +1,5 @@
name: CLI Node CI
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main and manual runs remain standalone.
on:
workflow_dispatch:
push:
@@ -9,7 +7,10 @@ on:
paths:
- 'cli/node/**'
- '.github/workflows/cli-node-ci.yml'
workflow_call:
pull_request:
paths:
- 'cli/node/**'
- '.github/workflows/cli-node-ci.yml'
jobs:
lint:
+3 -16
View File
@@ -1,24 +1,13 @@
name: Publish mem0-cli 🐍 distributions 📦 to PyPI
# Dispatched by release.yml (Release Router) when a release tagged cli-v* is
# published. Can also be dispatched manually to re-publish a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. cli-v0.2.0)'
required: true
type: string
prerelease:
description: 'Unused for PyPI (pre-releases are expressed in the version itself); accepted for router uniformity'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish mem0-cli 📦 to PyPI
if: startsWith(inputs.tag, 'cli-v')
if: startsWith(github.event.release.tag_name, 'cli-v')
runs-on: ubuntu-latest
permissions:
id-token: write
@@ -27,8 +16,6 @@ jobs:
working-directory: cli/python
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Set up Python
uses: actions/setup-python@v5
+4 -3
View File
@@ -1,7 +1,5 @@
name: CLI Python CI
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main and manual runs remain standalone.
on:
workflow_dispatch:
push:
@@ -9,7 +7,10 @@ on:
paths:
- 'cli/python/**'
- '.github/workflows/cli-python-ci.yml'
workflow_call:
pull_request:
paths:
- 'cli/python/**'
- '.github/workflows/cli-python-ci.yml'
jobs:
lint:
+6 -3
View File
@@ -6,10 +6,13 @@ name: docs - llms.txt check
# python scripts/check-llms-txt-coverage.py # read-only
# python scripts/check-llms-txt-coverage.py --write # scaffold placeholders
# On PRs this is invoked by ci-gate.yml (the single required check);
# manual runs remain standalone.
on:
workflow_call:
pull_request:
paths:
- 'docs/**/*.mdx'
- 'docs/llms.txt'
- 'scripts/check-llms-txt-coverage.py'
- 'scripts/llms-txt-ignore.txt'
workflow_dispatch: {}
permissions:
+6 -20
View File
@@ -1,35 +1,21 @@
name: Publish @mem0/openclaw-mem0 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged
# openclaw-v* is published. Can also be dispatched manually to re-publish
# a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. openclaw-v0.5.0)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish @mem0/openclaw-mem0 📦 to npm
if: startsWith(inputs.tag, 'openclaw-v')
if: startsWith(github.event.release.tag_name, 'openclaw-v')
runs-on: ubuntu-latest
permissions:
id-token: write
defaults:
run:
working-directory: integrations/openclaw
working-directory: openclaw
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -42,7 +28,7 @@ jobs:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
cache-dependency-path: openclaw/pnpm-lock.yaml
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -52,7 +38,7 @@ jobs:
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
+17 -16
View File
@@ -1,15 +1,16 @@
name: openclaw checks
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main and manual runs remain standalone.
on:
workflow_dispatch:
push:
branches: [main]
paths:
- 'integrations/openclaw/**'
- 'openclaw/**'
- '.github/workflows/openclaw-checks.yml'
pull_request:
paths:
- 'openclaw/**'
- '.github/workflows/openclaw-checks.yml'
workflow_call:
jobs:
lint:
@@ -27,13 +28,13 @@ jobs:
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
cache-dependency-path: openclaw/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/openclaw && pnpm install --frozen-lockfile
run: cd openclaw && pnpm install --frozen-lockfile
- name: Type check
run: cd integrations/openclaw && pnpm exec tsc --noEmit
run: cd openclaw && pnpm exec tsc --noEmit
test:
runs-on: ubuntu-latest
@@ -53,20 +54,20 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
cache-dependency-path: openclaw/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/openclaw && pnpm install --frozen-lockfile
run: cd openclaw && pnpm install --frozen-lockfile
- name: Run tests with coverage
run: cd integrations/openclaw && pnpm exec vitest run --coverage
run: cd openclaw && pnpm exec vitest run --coverage
- name: Upload coverage to Codecov
if: matrix.node-version == 20
uses: codecov/codecov-action@v4
with:
flags: openclaw
directory: integrations/openclaw/coverage
directory: openclaw/coverage
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -85,15 +86,15 @@ jobs:
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
cache-dependency-path: openclaw/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/openclaw && pnpm install --frozen-lockfile
run: cd openclaw && pnpm install --frozen-lockfile
- name: Build
run: cd integrations/openclaw && pnpm build
run: cd openclaw && pnpm build
- name: Verify dist output exists
run: |
test -f integrations/openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
test -f integrations/openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
test -f openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
test -f openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
-58
View File
@@ -1,58 +0,0 @@
name: Publish @mem0/opencode-plugin 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged
# opencode-v* is published. Can also be dispatched manually to re-publish
# a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. opencode-v0.2.0)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
jobs:
build-n-publish:
name: Build and publish @mem0/opencode-plugin 📦 to npm
if: startsWith(inputs.tag, 'opencode-v')
runs-on: ubuntu-latest
permissions:
id-token: write
defaults:
run:
working-directory: integrations/mem0-plugin/.opencode-plugin
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build
run: bun run build
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
npx npm@latest publish --provenance --access public
fi
@@ -1,39 +0,0 @@
name: opencode-plugin checks
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main and manual runs remain standalone.
on:
workflow_dispatch:
push:
branches: [main]
paths:
- 'integrations/mem0-plugin/.opencode-plugin/**'
- '.github/workflows/opencode-plugin-checks.yml'
workflow_call:
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: integrations/mem0-plugin/.opencode-plugin
steps:
- uses: actions/checkout@v4
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Type check
run: bun run type-check
- name: Build
run: bun run build
- name: Verify dist output exists
run: |
test -f dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
-60
View File
@@ -1,60 +0,0 @@
name: Publish @mem0/pi-agent-plugin 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged
# pi-agent-v* is published. Can also be dispatched manually to re-publish
# a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. pi-agent-v0.1.1)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
jobs:
build-n-publish:
name: Build and publish @mem0/pi-agent-plugin 📦 to npm
if: startsWith(inputs.tag, 'pi-agent-v')
runs-on: ubuntu-latest
permissions:
id-token: write
defaults:
run:
working-directory: integrations/pi-agent-plugin
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm build
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
npx npm@latest publish --provenance --access public
fi
@@ -1,92 +0,0 @@
name: pi-agent-plugin checks
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main and manual runs remain standalone.
on:
workflow_dispatch:
push:
branches: [main]
paths:
- 'integrations/pi-agent-plugin/**'
- '.github/workflows/pi-agent-plugin-checks.yml'
workflow_call:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Type check
run: cd integrations/pi-agent-plugin && pnpm exec tsc --noEmit
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Run tests
run: cd integrations/pi-agent-plugin && pnpm exec vitest run
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies
run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Build
run: cd integrations/pi-agent-plugin && pnpm build
- name: Verify dist output exists
run: |
test -f integrations/pi-agent-plugin/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
test -f integrations/pi-agent-plugin/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
test -f integrations/pi-agent-plugin/dist/entry.js || (echo "Build output missing: dist/entry.js" && exit 1)
test -f integrations/pi-agent-plugin/dist/entry.d.ts || (echo "Build output missing: dist/entry.d.ts" && exit 1)
-68
View File
@@ -1,68 +0,0 @@
name: Release Router 🚦
# Single entry point for all release publishing.
#
# Package CD workflows no longer listen to release events themselves — this
# router inspects the release tag and dispatches only the matching pipeline,
# so each release produces one routed run instead of one real run plus seven
# skipped ones.
#
# Re-publishing a release (e.g. after fixing registry settings) does NOT
# require deleting and recreating it anymore — manually dispatch the
# package's CD workflow from the tag instead:
#
# gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>
#
# Note: dispatching runs the workflow file as it exists at the given ref, so
# this router can only dispatch tags created after the workflow_dispatch
# conversion landed on main. For older tags, dispatch manually from main.
on:
release:
types: [published]
permissions:
actions: write
jobs:
route:
name: Route ${{ github.event.release.tag_name }} to its CD pipeline
runs-on: ubuntu-latest
steps:
- name: Match tag prefix to CD workflow
id: match
env:
TAG: ${{ github.event.release.tag_name }}
run: |
# Specific package prefixes first; the bare v* (Python SDK) arm
# must stay last so prefixed tags that also start with 'v'
# (vercel-ai-v*) can never be routed to the Python pipeline.
case "$TAG" in
ts-v*) workflow="ts-sdk-cd.yml" ;;
cli-node-v*) workflow="cli-node-cd.yml" ;;
cli-v*) workflow="cli-python-cd.yml" ;;
vercel-ai-v*) workflow="vercel-ai-cd.yml" ;;
openclaw-v*) workflow="openclaw-cd.yml" ;;
opencode-v*) workflow="opencode-plugin-cd.yml" ;;
pi-agent-v*) workflow="pi-agent-plugin-cd.yml" ;;
v*) workflow="cd.yml" ;;
*)
echo "::error::Release tag '$TAG' does not match any known package prefix — nothing will be published. See the tag prefix table in AGENTS.md."
exit 1
;;
esac
echo "workflow=$workflow" >> "$GITHUB_OUTPUT"
echo ":outbox_tray: Routed \`$TAG\` → \`$workflow\`" >> "$GITHUB_STEP_SUMMARY"
- name: Dispatch ${{ steps.match.outputs.workflow }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.event.release.tag_name }}
run: |
# --ref points at the tag so the dispatched run builds (and signs
# provenance for) the exact tagged commit.
gh workflow run "${{ steps.match.outputs.workflow }}" \
--repo "$GITHUB_REPOSITORY" \
--ref "refs/tags/$TAG" \
-f tag="$TAG" \
-f prerelease="${{ github.event.release.prerelease }}"
+4 -17
View File
@@ -1,24 +1,13 @@
name: Publish mem0ai 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged ts-v* is
# published. Can also be dispatched manually to re-publish a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. ts-v2.1.0)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish mem0ai 📦 to npm
if: startsWith(inputs.tag, 'ts-v')
if: startsWith(github.event.release.tag_name, 'ts-v')
runs-on: ubuntu-latest
permissions:
id-token: write
@@ -27,8 +16,6 @@ jobs:
working-directory: mem0-ts
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -51,7 +38,7 @@ jobs:
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
+3 -3
View File
@@ -1,14 +1,14 @@
name: TypeScript SDK CI
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main runs remain standalone.
on:
push:
branches: [main]
paths:
- 'mem0-ts/**'
- '.github/workflows/ts-sdk-ci.yml'
workflow_call:
pull_request:
paths:
- 'mem0-ts/**'
jobs:
check_changes:
+6 -20
View File
@@ -1,35 +1,21 @@
name: Publish @mem0/vercel-ai-provider 📦 to npm
# Dispatched by release.yml (Release Router) when a release tagged
# vercel-ai-v* is published. Can also be dispatched manually to re-publish
# a tag.
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag to build and publish (e.g. vercel-ai-v2.0.7)'
required: true
type: string
prerelease:
description: 'Publish under the version preid dist-tag instead of latest'
required: false
type: boolean
default: false
release:
types: [published]
jobs:
build-n-publish:
name: Build and publish @mem0/vercel-ai-provider 📦 to npm
if: startsWith(inputs.tag, 'vercel-ai-v')
if: startsWith(github.event.release.tag_name, 'vercel-ai-v')
runs-on: ubuntu-latest
permissions:
id-token: write
defaults:
run:
working-directory: integrations/vercel-ai-sdk
working-directory: vercel-ai-sdk
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -42,7 +28,7 @@ jobs:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache-dependency-path: integrations/vercel-ai-sdk/pnpm-lock.yaml
cache-dependency-path: vercel-ai-sdk/pnpm-lock.yaml
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -52,7 +38,7 @@ jobs:
- name: Publish to npm
run: |
if [ "${{ inputs.prerelease }}" = "true" ]; then
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID"
else
+1 -2
View File
@@ -170,6 +170,7 @@ cython_debug/
# Database
db
test-db
!embedchain/embedchain/core/db/
.vscode
.idea/
@@ -189,5 +190,3 @@ eval/
qdrant_storage/
.crossnote
testing.ipynb
.weave/
-4
View File
@@ -1,4 +0,0 @@
[submodule "evaluation"]
path = evaluation
url = https://github.com/mem0ai/memory-benchmarks
branch = main
+42 -68
View File
@@ -12,7 +12,7 @@ This file provides context for AI coding assistants (Claude Code, Cursor, GitHub
## Repository Structure
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, and documentation.
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, documentation, and evaluation tooling.
### Key Directories
@@ -22,18 +22,18 @@ This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs,
| `mem0-ts/` | TypeScript SDK (`mem0ai` on npm) — client + OSS memory |
| `cli/python/` | Python CLI (`mem0-cli` on PyPI) — Typer-based, entry point `mem0` |
| `cli/node/` | Node CLI (`@mem0/cli` on npm) — Commander-based, entry point `mem0` |
| `integrations/` | **Agent & editor integrations**, one directory per integration (see "Adding a New Integration") |
| `integrations/mem0-plugin/` | AI editor plugins (Claude Code, Cursor, Codex) — MCP server connection, lifecycle hooks, skills. Contains nested `.opencode-plugin/` (`@mem0/opencode-plugin`) |
| `integrations/openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors |
| `integrations/pi-agent-plugin/` | `@mem0/pi-agent-plugin` — Pi Agent plugin |
| `integrations/vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider |
| `vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider |
| `openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors |
| `server/` | FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + PostgreSQL/pgvector + Neo4j) |
| `openmemory/` | Self-hosted memory platform — `api/` (FastAPI + Alembic + MCP server) and `ui/` (Next.js 15 + React 19) |
| `skills/` | Claude Code skill definitions. Reference skills (SDK knowledge, always-on): `mem0/`, `mem0-cli/`, `mem0-vercel-ai-sdk/`. Pipeline skills (run on demand): `mem0-integrate/`, `mem0-test-integration/`, `mem0-oss-to-platform/` |
| `mem0-plugin/` | AI editor plugins (Claude Code, Cursor, Codex) — MCP server connection, lifecycle hooks, skills |
| `skills/` | Claude Code skill definitions. Reference skills (SDK knowledge, always-on): `mem0/`, `mem0-cli/`, `mem0-vercel-ai-sdk/`. Pipeline skills (run on demand): `mem0-integrate/`, `mem0-test-integration/` |
| `docs/` | Documentation site (Mintlify) |
| `tests/` | Python SDK tests (pytest) |
| `evaluation/` | Submodule → [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) — benchmarking (LOCOMO, LongMemEval, BEAM) lives in that repo |
| `examples/` | Sample projects & runnable demos — apps, Chrome extension, multi-agent patterns, and Jupyter notebooks (`notebooks/`) |
| `evaluation/` | Benchmarking framework — LOCOMO evals, experiment runner, score generation |
| `examples/` | Sample projects — demo apps, Chrome extension, multi-agent patterns |
| `cookbooks/` | Jupyter notebooks — customer support chatbot, AutoGen integration |
| `embedchain/` | Legacy Embedchain RAG framework (maintained separately, Poetry-based) |
| `pr-reviews/` | Pull request review materials |
| `scripts/` | Repo-wide utility scripts (e.g., `check-llms-txt-coverage.py` for docs/llms.txt sync) |
@@ -50,8 +50,8 @@ mem0 (Python SDK) mem0-ts (TypeScript SDK)
cli/python/ ──▶ mem0ai (optional, for OSS mode)
cli/node/ ──▶ mem0ai (npm, for API calls)
integrations/vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
integrations/openclaw/ ──▶ mem0ai (npm)
vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
openclaw/ ──▶ mem0ai (npm)
```
## Development Setup
@@ -74,8 +74,8 @@ pre-commit install # install git hooks
# TypeScript packages
cd mem0-ts && pnpm install # TS SDK
cd cli/node && pnpm install # Node CLI
cd integrations/vercel-ai-sdk && pnpm install # Vercel AI provider
cd integrations/openclaw && pnpm install # OpenClaw plugin
cd vercel-ai-sdk && pnpm install # Vercel AI provider
cd openclaw && pnpm install # OpenClaw plugin
```
## Build, Lint, and Test Commands
@@ -163,10 +163,10 @@ pnpm run dev # tsx src/index.ts (development)
- **Test:** vitest (not jest)
- **Framework:** Commander + Chalk + ora + cli-table3
### Vercel AI SDK Provider (`integrations/vercel-ai-sdk/`)
### Vercel AI SDK Provider (`vercel-ai-sdk/`)
```bash
cd integrations/vercel-ai-sdk
cd vercel-ai-sdk
pnpm install
pnpm run build # tsup
pnpm run lint # eslint
@@ -181,10 +181,10 @@ pnpm run test:node # vitest (node runtime)
- **Lint:** ESLint + Prettier
- **Test:** jest + vitest (edge/node configs)
### OpenClaw Plugin (`integrations/openclaw/`)
### OpenClaw Plugin (`openclaw/`)
```bash
cd integrations/openclaw
cd openclaw
pnpm install
pnpm run build # tsup
pnpm run test # vitest run
@@ -246,19 +246,18 @@ make docs # or: cd docs && mintlify dev
- **API spec:** `docs/openapi.json`
- **Structure:** `api-reference/`, `open-source/`, `platform/`, `integrations/`, `cookbooks/`, `core-concepts/`
### Evaluation / Benchmarking
Benchmarking lives in the external [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) repo (LOCOMO + LongMemEval + BEAM). The in-repo `evaluation/` path is a **git submodule** pinned to that repo's `main` — populate it with `git submodule update --init evaluation` (or clone mem0 with `--recurse-submodules`), or clone the benchmarks repo standalone:
### Evaluation (`evaluation/`)
```bash
git clone https://github.com/mem0ai/memory-benchmarks.git
cd memory-benchmarks
pip install -r requirements.txt
# Run a benchmark (Mem0 Cloud; use docker compose for OSS)
python -m benchmarks.locomo.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY
python -m benchmarks.longmemeval.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --all-questions
python -m benchmarks.beam.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --chat-sizes 100K --conversations 0-9
cd evaluation
make run-mem0-add # Run mem0 add experiments
make run-mem0-search # Run mem0 search experiments
make run-mem0-plus-add # With graph memory
make run-mem0-plus-search # With graph memory
make run-rag # RAG baseline
make run-full-context # Full context baseline
make run-langmem # LangMem comparison
make run-openai # OpenAI comparison
```
## Core APIs
@@ -331,7 +330,7 @@ python -m benchmarks.beam.run --project-name my-test --backend cloud --mem0-api-
- Root SDK: line length **120**
- Python CLI: line length **100** with extended rule set (UP, B, SIM, RUF)
- **isort** with `profile = "black"` for import sorting.
- Ruff excludes `openmemory/` from root config.
- Ruff excludes `embedchain/` and `openmemory/` from root config.
### TypeScript Conventions
@@ -344,8 +343,8 @@ python -m benchmarks.beam.run --project-name my-test --backend cloud --mem0-api-
|---------|--------|-----------|---------------|
| `mem0-ts/` | — | Prettier | jest |
| `cli/node/` | Biome | Biome | vitest |
| `integrations/vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
| `integrations/openclaw/` | — | — | vitest |
| `vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
| `openclaw/` | — | — | vitest |
### Type Checking
@@ -383,14 +382,14 @@ Model Context Protocol support in multiple places:
- **Remote:** MCP server at `mcp.mem0.ai`
- **Local:** MCP server in `openmemory/api/` (FastAPI-based)
- **Plugin:** MCP tools in `integrations/mem0-plugin/` — 9 tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`
- **Plugin:** MCP tools in `mem0-plugin/` — 9 tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`
### Plugin & Skills System
- `integrations/mem0-plugin/` provides integrations for Claude Code, Cursor, and Codex via MCP server connections and lifecycle hooks for automatic memory capture.
- `mem0-plugin/` provides integrations for Claude Code, Cursor, and Codex via MCP server connections and lifecycle hooks for automatic memory capture.
- `skills/` contains structured skill definitions for AI agents, split into two categories:
- **Reference skills** (always-on SDK knowledge): `mem0` (Python + TS SDKs, framework integrations), `mem0-cli` (terminal workflows), `mem0-vercel-ai-sdk` (Vercel AI provider).
- **Pipeline skills** (run on demand): `mem0-integrate` wires Mem0 into an existing repo via a TDD pipeline; `mem0-test-integration` verifies what the integrator produced on the same branch (the two are loosely coupled via `.mem0-integration/` artifacts); `mem0-oss-to-platform` migrates an existing project from Mem0 OSS to the hosted Platform SDK (plan, then execute on approval).
- **Pipeline skills** (run on demand): `mem0-integrate` wires Mem0 into an existing repo via a TDD pipeline; `mem0-test-integration` verifies what the integrator produced on the same branch. The two are loosely coupled via `.mem0-integration/` artifacts.
### Adding a New Provider
@@ -404,58 +403,32 @@ To add a new LLM, embedding, vector store, or reranker provider:
6. Add any new dependencies to the appropriate optional group in `pyproject.toml` (never to core `dependencies`)
7. Follow the exact pattern of existing providers in the same category — match method signatures, error handling, and config structure
### Adding a New Integration
Agent/editor integrations live under `integrations/`. Each is a self-contained directory (its own `package.json`/lockfile, build, and tests). To add one:
1. Create `integrations/<name>/` and build the integration there.
2. If it publishes to a registry, set `repository.directory: "integrations/<name>"` in its `package.json` so npm provenance links to the correct subdirectory.
3. Add CI/CD under `.github/workflows/` (`<name>-checks.yml`, `<name>-cd.yml`). Use `integrations/<name>` in `paths:` triggers, `working-directory`, and `cache-dependency-path`. Register the release tag prefix in the `case` block in `release.yml` (keep the bare `v*` arm last). Keep workflow **filenames** stable — npm OIDC trusted publishing is pinned to repo + workflow filename.
4. If it is a Claude Code / editor marketplace plugin, register its path in the five `marketplace.json` files (root + `.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/`, `.agents/plugins/`).
5. Document it under `docs/integrations/` and add the page to `docs/docs.json` and `docs/llms.txt`.
6. Add rows to the "Key Directories" table and the CI/CD tables in this file.
## CI/CD
### CI Workflows (automated testing)
PR testing is orchestrated by a single entry point: **`ci-gate.yml` (CI Gate)** runs on every PR, detects which packages changed, and invokes only the relevant package workflows below as reusable workflows (`workflow_call`). Its final **`CI Gate`** job aggregates the results (skipped pipelines pass; failed or cancelled ones fail) and is the **only status check that needs to be required** in branch protection. Package workflows keep their own push-to-main and manual triggers; their `pull_request` triggers moved into the gate's path filters.
| Workflow | File | Standalone Triggers | Tests |
|----------|------|---------------------|-------|
| CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates the workflows below |
| Python SDK | `ci.yml` | Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main (on `mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
| Python CLI | `cli-python-ci.yml` | Push to main (on `cli/python/`), manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
| Node CLI | `cli-node-ci.yml` | Push to main (on `cli/node/`), manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
| OpenClaw | `openclaw-checks.yml` | Push to main (on `integrations/openclaw/`), manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to main (on `integrations/mem0-plugin/.opencode-plugin/`), manual | Bun: tsc type-check + build + dist artifact check |
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to main (on `integrations/pi-agent-plugin/`), manual | tsc + vitest + tsup build (dist artifact check) on Node 20, 22 |
| docs llms.txt | `docs-llms-txt-check.yml` | Manual | `docs/llms.txt` coverage check |
When adding a new package CI workflow: give it `workflow_call` (plus `push`/`workflow_dispatch` as needed, but no `pull_request` trigger), then register it in `ci-gate.yml` — a path filter under the `changes` job, a call job, and an entry in the gate job's `needs` list.
| Workflow | File | Triggers | Tests |
|----------|------|----------|-------|
| Python SDK | `ci.yml` | Push to main, PRs on `mem0/`, `tests/`, `pyproject.toml` | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main, PRs on `mem0-ts/` | Prettier + build + jest on Node 20, 22 |
| Python CLI | `cli-python-ci.yml` | Push to `cli/python/`, PRs, manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
| Node CLI | `cli-node-ci.yml` | Push to `cli/node/`, PRs, manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
| OpenClaw | `openclaw-checks.yml` | Push to `openclaw/`, PRs, manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
| Embedchain | `ci.yml` (shared) | PRs on `embedchain/` | Ruff + pytest + coverage on Python 3.9–3.12 |
### CD Workflows (automated publishing)
Publishing is routed through a single entry point: **`release.yml` (Release Router)** is the only workflow that listens to `release: published` events. It matches the release tag prefix and dispatches the corresponding package workflow via `workflow_dispatch`, so each release produces exactly one routed run (no skipped runs from the other pipelines).
| Workflow | File | Tag Prefix | Target |
|----------|------|------------|--------|
| Release Router | `release.yml` | (all releases) | dispatches the matching workflow below |
| Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) |
| TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) |
| Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) |
| Node CLI | `cli-node-cd.yml` | `cli-node-v*` | npm (`@mem0/cli`) |
| Vercel AI SDK | `vercel-ai-cd.yml` | `vercel-ai-v*` | npm (`@mem0/vercel-ai-provider`) |
| OpenClaw | `openclaw-cd.yml` | `openclaw-v*` | npm (`@mem0/openclaw-mem0`) |
| OpenCode Plugin | `opencode-plugin-cd.yml` | `opencode-v*` | npm (`@mem0/opencode-plugin`) |
| Pi Agent Plugin | `pi-agent-plugin-cd.yml` | `pi-agent-v*` | npm (`@mem0/pi-agent-plugin`) |
- Package CD workflows are `workflow_dispatch`-only (inputs: `tag`, `prerelease`); they check out and build the given tag. Registry trusted-publisher settings stay pinned to each package's own workflow filename.
- All publishing uses **OIDC trusted publishing** — no tokens or secrets required.
- First publish of a new npm package must be done manually; OIDC works for subsequent versions.
- To re-publish a release (e.g. after a registry settings fix), do **not** delete/recreate the GitHub release — manually dispatch the package workflow instead: `gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>`.
- When adding a new package: add its CD workflow (`workflow_dispatch` with `tag`/`prerelease` inputs), then register its tag prefix in the `case` block in `release.yml`. Keep the bare `v*` arm last.
### Utility Workflows
@@ -603,6 +576,7 @@ N/A
- Modify CI/CD workflows without explicit approval.
- Add new Python dependencies to the core `dependencies` list in `pyproject.toml` without discussion — use optional dependency groups instead.
- Commit `.env` files, API keys, or credentials.
- Modify `embedchain/` unless specifically working on that package — it has its own build system (Poetry).
- Skip pre-commit hooks.
- Use npm or yarn in TypeScript packages — this repo uses pnpm exclusively.
- Use `require()` for imports in TypeScript — use ES module `import` syntax.
+1 -2
View File
@@ -1026,8 +1026,7 @@ def get_user_preferences(user_id: str):
### AutoGen Integration
```python
# Mem0Teachability lives in examples/notebooks/helper/ — see examples/notebooks/mem0-autogen.ipynb
from helper.mem0_teachability import Mem0Teachability
from cookbooks.helper.mem0_teachability import Mem0Teachability
from mem0 import Memory
# Add memory capability to AutoGen agents
+221
View File
@@ -0,0 +1,221 @@
# Migration Guide: Upgrading to mem0 1.0.0
## TL;DR
**What changed?** We simplified the API by removing confusing version parameters. Now everything returns a consistent format: `{"results": [...]}`.
**What you need to do:**
1. Upgrade: `pip install mem0ai==1.0.0`
2. Remove `version` and `output_format` parameters from your code
3. Update response handling to use `result["results"]` instead of treating responses as lists
**Time needed:** ~5-10 minutes for most projects
---
## Quick Migration Guide
### 1. Install the Update
```bash
pip install mem0ai==1.0.0
```
### 2. Update Your Code
**If you're using the Memory API:**
```python
# Before
memory = Memory(config=MemoryConfig(version="v1.1"))
result = memory.add("I like pizza")
# After
memory = Memory() # That's it - version is automatic now
result = memory.add("I like pizza")
```
**If you're using the Client API:**
```python
# Before
client.add(messages, output_format="v1.1")
client.search(query, version="v2", output_format="v1.1")
# After
client.add(messages) # Just remove those extra parameters
client.search(query)
```
### 3. Update How You Handle Responses
All responses now use the same format: a dictionary with `"results"` key.
```python
# Before - you might have done this
result = memory.add("I like pizza")
for item in result: # Treating it as a list
print(item)
# After - do this instead
result = memory.add("I like pizza")
for item in result["results"]: # Access the results key
print(item)
# Graph relations (if you use them)
if "relations" in result:
for relation in result["relations"]:
print(relation)
```
---
## Enhanced Message Handling
The platform client (MemoryClient) now supports the same flexible message formats as the OSS version:
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-key")
# All three formats now work:
# 1. Single string (automatically converted to user message)
client.add("I like pizza", user_id="alice")
# 2. Single message dictionary
client.add({"role": "user", "content": "I like pizza"}, user_id="alice")
# 3. List of messages (conversation)
client.add([
{"role": "user", "content": "I like pizza"},
{"role": "assistant", "content": "I'll remember that!"}
], user_id="alice")
```
### Async Mode Configuration
The `async_mode` parameter now defaults to `True` but can be configured:
```python
# Default behavior (async_mode=True)
client.add(messages, user_id="alice")
# Explicitly set async mode
client.add(messages, user_id="alice", async_mode=True)
# Disable async mode if needed
client.add(messages, user_id="alice", async_mode=False)
```
**Note:** `async_mode=True` provides better performance for most use cases. Only set it to `False` if you have specific synchronous processing requirements.
---
## That's It!
For most users, that's all you need to know. The changes are:
- ✅ No more `version` or `output_format` parameters
- ✅ Consistent `{"results": [...]}` response format
- ✅ Cleaner, simpler API
---
## Common Issues
**Getting `KeyError: 'results'`?**
Your code is still treating the response as a list. Update it:
```python
# Change this:
for memory in response:
# To this:
for memory in response["results"]:
```
**Getting `TypeError: unexpected keyword argument`?**
You're still passing old parameters. Remove them:
```python
# Change this:
client.add(messages, output_format="v1.1")
# To this:
client.add(messages)
```
**Seeing deprecation warnings?**
Remove any explicit `version="v1.0"` from your config:
```python
# Change this:
memory = Memory(config=MemoryConfig(version="v1.0"))
# To this:
memory = Memory()
```
---
## What's New in 1.0.0
- **Better vector stores:** Fixed OpenSearch and improved reliability across all stores
- **Cleaner API:** One way to do things, no more confusing options
- **Enhanced GCP support:** Better Vertex AI configuration options
- **Flexible message input:** Platform client now accepts strings, dicts, and lists (aligned with OSS)
- **Configurable async_mode:** Now defaults to `True` but users can override if needed
---
## Need Help?
- Check [GitHub Issues](https://github.com/mem0ai/mem0/issues)
- Read the [documentation](https://docs.mem0.ai/)
- Open a new issue if you're stuck
---
## Advanced: Configuration Changes
**If you configured vector stores with version:**
```python
# Before
config = MemoryConfig(
version="v1.1",
vector_store=VectorStoreConfig(...)
)
# After
config = MemoryConfig(
vector_store=VectorStoreConfig(...)
)
```
---
## Testing Your Migration
Quick sanity check:
```python
from mem0 import Memory
memory = Memory()
# Add should return a dict with "results"
result = memory.add("I like pizza", user_id="test")
assert "results" in result
# Search should return a dict with "results"
search = memory.search("food", user_id="test")
assert "results" in search
# Get all should return a dict with "results"
all_memories = memory.get_all(user_id="test")
assert "results" in all_memories
print("✅ Migration successful!")
```
+2 -22
View File
@@ -86,25 +86,7 @@ See the [migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for upgra
## 🚀 Quickstart Guide <a name="quickstart"></a>
### Sign up as an agent
AI agents can mint a working Mem0 API key in under five seconds — no email, no dashboard, no OTP. Four commands end-to-end:
```bash
# 1. Install
npm install -g @mem0/cli # or: pip install mem0-cli
# 2. Sign up as an agent (replace `claude-code` with your name)
mem0 init --agent --agent-caller claude-code
# 3. Add a memory
mem0 add "I am using mem0"
# 4. Search
mem0 search "am I using mem0"
```
The human owner can claim the account later with `mem0 init --email <their-email>` — same key, memories preserved. Full guide: [Sign up as an agent](https://docs.mem0.ai/platform/agent-signup).
> **Agent Mode — for AI agents setting up Mem0 autonomously.** Run `mem0 init --agent --agent-caller <your-name> --json` (after `pip install mem0-cli` or `npm install -g @mem0/cli`), replacing `<your-name>` with your AI agent identity (e.g. `claude-code`, `cursor`, `codex`). This mints an evaluation Mem0 API key in <5 seconds — no email, no dashboard, no OTP. If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init. Use the key immediately against the Platform or the MCP server. The human owner can claim ownership later with `mem0 init --email <their-email>`: memories transfer, the same key keeps working, and the agent isn't disrupted.
| | Library | Self-Hosted Server | Cloud Platform |
|---|---------|-------------------|----------------|
@@ -153,7 +135,6 @@ See the [self-hosted docs](https://docs.mem0.ai/open-source/overview) for config
1. Sign up on [Mem0 Platform](https://app.mem0.ai?utm_source=oss&utm_medium=readme)
2. Embed the memory layer via SDK or API keys
3. Using hosted Qdrant vectors? See the [Platform migration guide](https://docs.mem0.ai/migration/oss-to-platform) to import them into Mem0 Platform.
### CLI
@@ -186,10 +167,9 @@ npx skills add https://github.com/mem0ai/mem0 --skill mem0-vercel-ai-sdk
```bash
npx skills add https://github.com/mem0ai/mem0 --skill mem0-integrate
npx skills add https://github.com/mem0ai/mem0 --skill mem0-test-integration
npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
```
Use `/mem0-integrate` to wire Mem0 into an existing repo via a test-first pipeline, then `/mem0-test-integration` to verify. Use `/mem0-oss-to-platform` to migrate an existing project from Mem0 OSS to the hosted Platform SDK. See the [skills catalog](./skills/) or [Vibecoding with Mem0](https://docs.mem0.ai/vibecoding) for the full picture.
Use `/mem0-integrate` to wire Mem0 into an existing repo via a test-first pipeline, then `/mem0-test-integration` to verify. See the [skills catalog](./skills/) or [Vibecoding with Mem0](https://docs.mem0.ai/vibecoding) for the full picture.
### Basic Usage
-51
View File
@@ -1,51 +0,0 @@
# Changelog
All notable changes to `@mem0/cli` are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.8] — 2026-06-01
### Security
- Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs:
- `jws` → 4.0.1 (CVE-2025-65945)
- `langsmith` → ^0.6.0 (CVE-2026-45134)
- `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343)
- `picomatch` → ^2.3.2 (CVE-2026-33671)
- `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996)
- `path-to-regexp` → ^8.4.0 (CVE-2026-4926)
- `rollup` → ^4.59.0 (CVE-2026-27606)
- `glob` → ^10.5.0 (CVE-2025-64756)
- `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
## [0.2.7] — 2026-05-20
### Added
- `mem0 whoami` — print the active agent's `default_user_id` (the AGENTRUSH
leaderboard identifier). Reads from local config, no network call.
- `mem0 agent-rush <add | search>` — subcommand group that wraps the new
`/v1/agent-rush/` platform endpoints for the 7-day AGENTRUSH game. Project
routing is implicit (resolved server-side); no flags exposed. Pretty-prints
platform error codes into actionable hints (e.g. `agentrush_search_first`
→ "Run 3 'mem0 agent-rush search' commands before adding.").
- PII safety prompt on first `mem0 agent-rush add`. Interactive runs require
explicit `y` to acknowledge that AGENTRUSH memories are public; the
acknowledgement is persisted in `~/.mem0/config.json` under
`agent_rush.acknowledged_at` so the prompt only appears once per machine.
Non-interactive (agent) invocations surface the warning to stderr without
blocking.
- New config schema field: `agent_rush.acknowledged_at` (ISO timestamp,
empty until first interactive acknowledgement).
### Changed
- HTTP requests from the new agent-rush commands send `X-Mem0-Mode: agent-rush`
in addition to the existing source headers, so platform telemetry can split
game traffic from regular CLI usage.
## [0.2.6] and earlier
Unlogged historical releases. See git history under `cli/node/`.
+2 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@mem0/cli",
"version": "0.2.8",
"version": "0.2.5",
"description": "The official CLI for mem0 — the memory layer for AI agents",
"type": "module",
"bin": {
@@ -40,19 +40,8 @@
"typescript": "^5.4.0",
"tsup": "^8.0.0",
"tsx": "^4.7.0",
"vite": "^6.0.0",
"vitest": "^4.1.0",
"vitest": "^1.5.0",
"@biomejs/biome": "^1.7.0",
"@types/node": "^20.0.0"
},
"pnpm": {
"overrides": {
"jws@4.0.0": "4.0.1",
"langsmith@<0.6.0": "^0.6.0",
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4",
"picomatch@<2.3.2": "^2.3.2",
"postcss@<8.5.10": ">=8.5.10",
"esbuild": ">=0.28.1"
}
}
}
+724 -311
View File
File diff suppressed because it is too large Load Diff
-14
View File
@@ -1,14 +0,0 @@
packages:
- '.'
onlyBuiltDependencies:
- "@biomejs/biome"
- esbuild
overrides:
jws@4.0.0: 4.0.1
langsmith@<0.6.0: ^0.6.0
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
picomatch@<2.3.2: ^2.3.2
"postcss@<8.5.10": ">=8.5.10"
"esbuild": ">=0.28.1"
+1 -1
View File
@@ -247,7 +247,7 @@ export async function claimViaOtp(
printError(`Claim failed: ${detail}`);
if (errCode === "email_already_claimed") {
console.log(
` ${dim("Tip: this email already has a Mem0 account. Sign in at app.mem0.ai with your existing credentials.")}`,
` ${dim("Tip: this email already has a Mem0 account. Sign in there and run `mem0 link <key>` to attach this agent.")}`,
);
}
process.exit(1);
-147
View File
@@ -1,147 +0,0 @@
/**
* `mem0 agent-rush <add|search> "..."` — wraps the AGENTRUSH platform endpoints.
* Project routing is implicit (server-side); zero flags needed.
*/
import readline from "node:readline";
import { colors, printError, printSuccess } from "../branding.js";
import { loadConfig, saveConfig } from "../config.js";
import { CLI_VERSION } from "../version.js";
const PII_WARNING = [
"",
"⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.",
" Do not include real names, emails, secrets, work content, or PII.",
"",
].join("\n");
const ERROR_HINTS: Record<string, string> = {
agentrush_search_first:
"Run 3 'mem0 agent-rush search' commands before adding.",
agentrush_search_quota: "You've used your 3 lifetime searches.",
agentrush_add_quota: "You've used your 3 lifetime adds.",
agentrush_not_agent_mode:
"Re-run 'mem0 init --agent' to bootstrap an agent-mode key.",
agentrush_length: "Memory text must be 50-1000 characters.",
agentrush_no_urls: "URLs are not allowed.",
agentrush_blocklist: "Content contains a blocked term.",
agentrush_global_quota: "Event-wide cap reached. Try again later.",
agentrush_not_provisioned:
"AGENTRUSH is not provisioned in this environment.",
};
async function callEndpoint(
path: string,
body: Record<string, unknown>,
): Promise<unknown> {
const config = loadConfig();
const baseUrl = (config.platform?.baseUrl ?? "https://api.mem0.ai").replace(
/\/+$/,
"",
);
if (!config.platform?.apiKey) {
printError("Not initialized. Run `mem0 init --agent` first.");
process.exit(1);
}
const resp = await fetch(`${baseUrl}${path}`, {
method: "POST",
headers: {
Authorization: `Token ${config.platform.apiKey}`,
"Content-Type": "application/json",
"X-Mem0-Source": "cli",
"X-Mem0-Client-Language": "node",
"X-Mem0-Client-Version": CLI_VERSION,
"X-Mem0-Mode": "agent-rush",
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
const json = await resp.json().catch(() => ({}));
if (!resp.ok) {
const code =
(json as { error?: { code?: string } }).error?.code ?? "unknown";
printError(`AGENTRUSH error: ${code}`);
if (ERROR_HINTS[code]) {
console.log(` ${colors.dim(ERROR_HINTS[code])}`);
}
process.exit(1);
}
return json;
}
function promptLine(question: string): Promise<string> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer.trim());
});
});
}
/**
* Ensure the human has acknowledged that AGENTRUSH memories are PUBLIC.
*
* Interactive (TTY): show the prompt; on "y" persist `agentRush.acknowledgedAt`
* so we never ask the same machine twice. On anything else, abort.
*
* Non-interactive (agent invocation, no TTY): print the warning to stderr
* for the human reading the agent's transcript and proceed — agents can't
* answer y/N prompts.
*/
async function ensureWarningAcknowledged(): Promise<void> {
const config = loadConfig();
if (config.agentRush?.acknowledgedAt) return;
if (!process.stdin.isTTY || !process.stdout.isTTY) {
// Agent context: surface the warning to stderr, don't block.
console.error(PII_WARNING);
return;
}
console.log(PII_WARNING);
const answer = (await promptLine(" Continue? [y/N]: ")).toLowerCase();
if (answer !== "y" && answer !== "yes") {
printError("Aborted.");
process.exit(1);
}
config.agentRush.acknowledgedAt = new Date().toISOString();
saveConfig(config);
}
export async function cmdAgentRushAdd(content: string): Promise<void> {
await ensureWarningAcknowledged();
const result = await callEndpoint("/v1/agent-rush/memories/", { content });
printSuccess(
`Memory submitted (event_id: ${(result as { event_id?: string }).event_id ?? "?"})`,
);
}
export async function cmdAgentRushSearch(query: string): Promise<void> {
const result = (await callEndpoint("/v1/agent-rush/memories/search/", {
query,
})) as {
results?: Array<{ memory?: string }>;
memories?: Array<{ memory?: string }>;
};
const memories = result.results ?? result.memories ?? [];
if (memories.length === 0) {
console.log(colors.dim("(no results)"));
return;
}
memories.slice(0, 5).forEach((m, i) => {
console.log(` ${i + 1}. ${m.memory ?? JSON.stringify(m)}`);
});
}
+2 -2
View File
@@ -46,7 +46,7 @@ export async function cmdAdd(
file?: string;
metadata?: string;
immutable: boolean;
infer?: boolean;
noInfer: boolean;
expires?: string;
categories?: string;
output: string;
@@ -136,7 +136,7 @@ export async function cmdAdd(
runId: opts.runId,
metadata: meta,
immutable: opts.immutable,
infer: opts.infer !== false,
infer: !opts.noInfer,
expires: opts.expires,
categories: cats,
});
-18
View File
@@ -1,18 +0,0 @@
/**
* `mem0 whoami` — print the active agent's default_user_id (AGENTRUSH identifier).
* Reads from local config; no network call.
*/
import { colors, printError, printInfo } from "../branding.js";
import { loadConfig } from "../config.js";
export async function cmdWhoami(): Promise<void> {
const config = loadConfig();
const sessionId = config.platform?.defaultUserId;
if (!sessionId) {
printError("No default_user_id found. Run `mem0 init --agent` first.");
process.exit(1);
}
console.log(`Your AGENTRUSH identifier: ${colors.brand(sessionId)}`);
printInfo("Find your row at https://mem0.ai/agentrush");
}
-15
View File
@@ -40,18 +40,11 @@ export interface TelemetryConfig {
anonymousId: string;
}
export interface AgentRushConfig {
// ISO timestamp the human acknowledged the "memories are public" warning.
// Empty until first interactive `mem0 agent-rush add`.
acknowledgedAt: string;
}
export interface Mem0Config {
version: number;
defaults: DefaultsConfig;
platform: PlatformConfig;
telemetry: TelemetryConfig;
agentRush: AgentRushConfig;
}
export function createDefaultConfig(): Mem0Config {
@@ -76,9 +69,6 @@ export function createDefaultConfig(): Mem0Config {
telemetry: {
anonymousId: "",
},
agentRush: {
acknowledgedAt: "",
},
};
}
@@ -113,8 +103,6 @@ export function loadConfig(): Mem0Config {
config.defaults.runId = defaults.run_id ?? "";
const telemetry = data.telemetry ?? {};
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
const agentRush = data.agent_rush ?? {};
config.agentRush.acknowledgedAt = agentRush.acknowledged_at ?? "";
}
// Environment variable overrides
@@ -155,9 +143,6 @@ export function saveConfig(config: Mem0Config): void {
telemetry: {
anonymous_id: config.telemetry.anonymousId,
},
agent_rush: {
acknowledged_at: config.agentRush.acknowledgedAt,
},
};
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2));
-42
View File
@@ -262,48 +262,6 @@ program
await runIdentify(name);
});
// ── Setup: whoami (print active agent identifier) ────────────────────────
program
.command("whoami")
.description("Print the active agent's AGENTRUSH identifier.")
.action(async () => {
const { cmdWhoami } = await import("./commands/whoami.js");
await cmdWhoami();
});
// ── AGENTRUSH subcommand group ────────────────────────────────────────────
const agentRush = program
.command("agent-rush")
.description("AGENTRUSH game commands.")
.addHelpCommand(false)
.configureHelp({ formatHelp: richFormatHelp });
agentRush
.command("add <content...>")
.description("Submit a memory to AGENTRUSH.")
.addHelpText(
"after",
'\nExamples:\n $ mem0 agent-rush add "I used mem0 to build a coding agent"\n $ mem0 agent-rush add "Agents that remember are better agents"',
)
.action(async (parts: string[]) => {
const { cmdAgentRushAdd } = await import("./commands/agent-rush.js");
await cmdAgentRushAdd(parts.join(" "));
});
agentRush
.command("search <query...>")
.description("Search AGENTRUSH memories.")
.addHelpText(
"after",
'\nExamples:\n $ mem0 agent-rush search "agents and memory and tools"\n $ mem0 agent-rush search "coding assistant"',
)
.action(async (parts: string[]) => {
const { cmdAgentRushSearch } = await import("./commands/agent-rush.js");
await cmdAgentRushSearch(parts.join(" "));
});
// ── Memory: add ───────────────────────────────────────────────────────────
program
+16 -48
View File
@@ -3,7 +3,6 @@
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { Command } from "commander";
import { createMockBackend } from "./setup.js";
import type { Backend } from "../src/backend/base.js";
import { setAgentMode } from "../src/state.js";
@@ -42,6 +41,8 @@ describe("cmdAdd", () => {
await cmdAdd(mockBackend, "I prefer dark mode", {
userId: "alice",
immutable: false,
noInfer: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledOnce();
@@ -53,6 +54,8 @@ describe("cmdAdd", () => {
userId: "alice",
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
immutable: false,
noInfer: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledOnce();
@@ -63,6 +66,8 @@ describe("cmdAdd", () => {
await cmdAdd(mockBackend, "test", {
userId: "alice",
immutable: false,
noInfer: false,
output: "json",
});
expect(output).toContain("results");
@@ -73,59 +78,14 @@ describe("cmdAdd", () => {
await cmdAdd(mockBackend, "test", {
userId: "alice",
immutable: false,
noInfer: false,
output: "quiet",
});
expect(output).not.toContain("dark mode");
});
});
describe("cmdAdd forwards --no-infer (regression for #5261)", () => {
it("forwards infer: false when --no-infer is set", async () => {
const { cmdAdd } = await import("../src/commands/memory.js");
// `infer: false` is the shape Commander produces for `--no-infer`.
await cmdAdd(mockBackend, "store me verbatim", {
userId: "alice",
immutable: false,
infer: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledWith(
"store me verbatim",
undefined,
expect.objectContaining({ infer: false }),
);
});
it("forwards infer: true by default (flag absent)", async () => {
const { cmdAdd } = await import("../src/commands/memory.js");
await cmdAdd(mockBackend, "infer me", {
userId: "alice",
immutable: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledWith(
"infer me",
undefined,
expect.objectContaining({ infer: true }),
);
});
it("Commander stores --no-infer as opts.infer, not opts.noInfer", () => {
// Pins the assumption the fix relies on: Commander's `--no-X` option
// populates the positive camelCase key (`infer`), never `noInfer`.
const withFlag = new Command();
withFlag.option("--no-infer", "Skip inference, store raw.").action(() => {});
withFlag.parse(["--no-infer"], { from: "user" });
expect(withFlag.opts().infer).toBe(false);
expect(withFlag.opts().noInfer).toBeUndefined();
const withoutFlag = new Command();
withoutFlag.option("--no-infer", "Skip inference, store raw.").action(() => {});
withoutFlag.parse([], { from: "user" });
expect(withoutFlag.opts().infer).toBe(true);
});
});
describe("cmdAdd deduplicates PENDING", () => {
const DUPLICATE_PENDING = {
results: [
@@ -140,6 +100,8 @@ describe("cmdAdd deduplicates PENDING", () => {
await cmdAdd(mockBackend, "test", {
userId: "alice",
immutable: false,
noInfer: false,
output: "text",
});
expect(output.match(/Queued/g)?.length).toBe(1);
@@ -151,6 +113,8 @@ describe("cmdAdd deduplicates PENDING", () => {
await cmdAdd(mockBackend, "test", {
userId: "alice",
immutable: false,
noInfer: false,
output: "json",
});
const data = JSON.parse(output);
@@ -165,6 +129,8 @@ describe("cmdAdd deduplicates PENDING", () => {
await cmdAdd(mockBackend, "test", {
userId: "alice",
immutable: false,
noInfer: false,
output: "agent",
});
const data = JSON.parse(output);
@@ -349,6 +315,8 @@ describe("agent mode", () => {
await cmdAdd(mockBackend, "test preference", {
userId: "alice",
immutable: false,
noInfer: false,
output: "agent",
});
const parsed = JSON.parse(output.trim());
-6
View File
@@ -8,10 +8,4 @@ export default defineConfig({
define: {
__CLI_VERSION__: JSON.stringify(pkg.version),
},
test: {
// Integration tests spawn the CLI via `npx tsx` (15s subprocess
// timeout); the first spawn in a file pays a cold-start cost that can
// exceed vitest's 5s default on CI runners.
testTimeout: 30_000,
},
});
-36
View File
@@ -1,36 +0,0 @@
# Changelog
All notable changes to `mem0-cli` (Python) are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.7] — 2026-05-20
### Added
- `mem0 whoami` — print the active agent's `default_user_id` (the AGENTRUSH
leaderboard identifier). Reads from local config, no network call.
- `mem0 agent-rush <add | search>` — subcommand group that wraps the new
`/v1/agent-rush/` platform endpoints for the 7-day AGENTRUSH game. Project
routing is implicit (resolved server-side); no flags exposed. Pretty-prints
platform error codes into actionable hints (e.g. `agentrush_search_first`
→ "Run 3 'mem0 agent-rush search' commands before adding.").
- PII safety prompt on first `mem0 agent-rush add`. Interactive runs require
explicit `y` to acknowledge that AGENTRUSH memories are public; the
acknowledgement is persisted in `~/.mem0/config.json` under
`agent_rush.acknowledged_at` so the prompt only appears once per machine.
Non-interactive (agent) invocations surface the warning to stderr without
blocking.
- New config schema field: `agent_rush.acknowledged_at` (ISO timestamp,
empty until first interactive acknowledgement).
### Changed
- HTTP requests from the new agent-rush commands send `X-Mem0-Mode: agent-rush`
in addition to the existing source headers, so platform telemetry can split
game traffic from regular CLI usage.
## [0.2.6] and earlier
Unlogged historical releases. See git history under `cli/python/`.
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "mem0-cli"
version = "0.2.7"
version = "0.2.5"
description = "The official CLI for mem0 — the memory layer for AI agents"
readme = "README.md"
license = "Apache-2.0"
-59
View File
@@ -914,65 +914,6 @@ def identify(
run_identify(name)
@app.command(name="whoami", rich_help_panel="Setup")
def whoami_cmd() -> None:
"""Print your AGENTRUSH identifier (default_user_id).
Example:
mem0 whoami
"""
from mem0_cli.commands.whoami_cmd import run_whoami
run_whoami()
# ── AGENTRUSH sub-app ─────────────────────────────────────────────────────
agent_rush_app = typer.Typer(
name="agent-rush",
help="AGENTRUSH game commands",
no_args_is_help=True,
rich_markup_mode="rich",
)
@agent_rush_app.callback(invoke_without_command=True)
def _agent_rush_callback(ctx: typer.Context) -> None:
if ctx.invoked_subcommand:
_fire_telemetry(f"agent-rush.{ctx.invoked_subcommand}")
@agent_rush_app.command(name="add")
def agent_rush_add(
content: str = typer.Argument(..., help="Memory content (50-1000 characters, no URLs)."),
) -> None:
"""Submit a memory to AGENTRUSH.
Example:
mem0 agent-rush add "I enjoy solving constraint-satisfaction problems."
"""
from mem0_cli.commands.agent_rush_cmd import run_agent_rush_add
run_agent_rush_add(content)
@agent_rush_app.command(name="search")
def agent_rush_search(
query: str = typer.Argument(..., help="Search query."),
) -> None:
"""Search AGENTRUSH memories.
Example:
mem0 agent-rush search "constraint satisfaction"
"""
from mem0_cli.commands.agent_rush_cmd import run_agent_rush_search
run_agent_rush_search(query)
app.add_typer(agent_rush_app, name="agent-rush", rich_help_panel="Setup")
# (entity_app registered at module level, below sub-group definitions)
@@ -218,7 +218,7 @@ def claim_via_otp(config: Mem0Config, *, email: str, code: str | None = None) ->
print_error(err_console, f"Claim failed: {detail}")
if code_str == "email_already_claimed":
console.print(
f" [{DIM_COLOR}]Tip: this email already has a Mem0 account. Sign in at app.mem0.ai with your existing credentials.[/]"
f" [{DIM_COLOR}]Tip: this email already has a Mem0 account. Sign in there and run `mem0 link <key>` to attach this agent.[/]"
)
raise typer.Exit(1)
@@ -1,132 +0,0 @@
"""mem0 agent-rush — AGENTRUSH game commands.
Wraps the platform's /v1/agent-rush/{memories/, memories/search/} endpoints.
Hardcoded routing; no flags needed.
"""
from __future__ import annotations
import sys
from datetime import datetime, timezone
import httpx
import typer
from rich.console import Console
from mem0_cli.branding import print_error, print_success
from mem0_cli.config import load_config, save_config
console = Console()
err_console = Console(stderr=True)
_PII_WARNING_LINES = (
"",
"[yellow]⚠️ AGENTRUSH memories are PUBLIC — visible to any other player.[/yellow]",
"[yellow] Do not include real names, emails, secrets, work content, or PII.[/yellow]",
"",
)
_SOURCE_HEADERS = {
"X-Mem0-Source": "cli",
"X-Mem0-Client-Language": "python",
"X-Mem0-Mode": "agent-rush",
}
_ERROR_HINTS = {
"agentrush_search_first": "Run 3 'mem0 agent-rush search' commands before adding.",
"agentrush_search_quota": "You've used your 3 lifetime searches.",
"agentrush_add_quota": "You've used your 3 lifetime adds.",
"agentrush_not_agent_mode": "Re-run 'mem0 init --agent' to bootstrap an agent-mode key.",
"agentrush_length": "Memory text must be 50-1000 characters.",
"agentrush_no_urls": "URLs are not allowed.",
"agentrush_blocklist": "Content contains a blocked term.",
"agentrush_global_quota": "Event-wide cap reached. Try again later.",
"agentrush_not_provisioned": "AGENTRUSH is not provisioned in this environment.",
}
def _call(path: str, body: dict) -> dict:
config = load_config()
if not config.platform.api_key:
print_error(err_console, "Not initialized. Run `mem0 init --agent` first.")
raise typer.Exit(1)
base_url = (config.platform.base_url or "https://api.mem0.ai").rstrip("/")
try:
with httpx.Client(timeout=30.0) as client:
resp = client.post(
f"{base_url}{path}",
headers={
**_SOURCE_HEADERS,
"Authorization": f"Token {config.platform.api_key}",
"Content-Type": "application/json",
},
json=body,
)
except httpx.HTTPError as exc:
print_error(err_console, f"Network error: {exc}")
raise typer.Exit(1) from exc
try:
data = resp.json()
except Exception:
data = {}
if resp.status_code >= 400:
code = (
(data.get("error") or {}).get("code", "unknown")
if isinstance(data, dict)
else "unknown"
)
print_error(err_console, f"AGENTRUSH error: {code}")
hint = _ERROR_HINTS.get(code)
if hint:
console.print(f" [dim]{hint}[/dim]")
raise typer.Exit(1)
return data
def _ensure_warning_acknowledged() -> None:
"""Block the first interactive add on the PII warning; pass-through for agents.
Interactive (TTY): show prompt, require explicit 'y', persist
`agent_rush.acknowledged_at` so we never ask the same machine twice.
Non-interactive (no TTY — typical when an agent runs the CLI): surface
the warning to stderr for the human reading the agent transcript and
proceed without prompting (agents can't answer y/N).
"""
config = load_config()
if config.agent_rush.acknowledged_at:
return
is_tty = sys.stdin.isatty() and sys.stdout.isatty()
if not is_tty:
for line in _PII_WARNING_LINES:
err_console.print(line)
return
for line in _PII_WARNING_LINES:
console.print(line)
answer = typer.prompt(" Continue? [y/N]", default="N", show_default=False).strip().lower()
if answer not in ("y", "yes"):
print_error(err_console, "Aborted.")
raise typer.Exit(1)
config.agent_rush.acknowledged_at = datetime.now(timezone.utc).isoformat()
save_config(config)
def run_agent_rush_add(content: str) -> None:
_ensure_warning_acknowledged()
result = _call("/v1/agent-rush/memories/", {"content": content})
event_id = result.get("event_id", "?")
print_success(console, f"Memory submitted (event_id: {event_id})")
def run_agent_rush_search(query: str) -> None:
result = _call("/v1/agent-rush/memories/search/", {"query": query})
memories = result.get("results") or result.get("memories") or []
if not memories:
console.print("[dim](no results)[/dim]")
return
for i, m in enumerate(memories[:5], start=1):
text = m.get("memory") if isinstance(m, dict) else str(m)
console.print(f" {i}. {text}")
@@ -1,25 +0,0 @@
"""mem0 whoami — print the active agent's default_user_id (AGENTRUSH identifier)."""
from __future__ import annotations
import typer
from rich.console import Console
from mem0_cli.branding import BRAND_COLOR, print_error, print_info
from mem0_cli.config import load_config
console = Console()
err_console = Console(stderr=True)
def run_whoami() -> None:
config = load_config()
session_id = config.platform.default_user_id if config.platform else None
if not session_id:
print_error(
err_console,
"No default_user_id found. Run `mem0 init --agent` first.",
)
raise typer.Exit(1)
console.print(f"Your AGENTRUSH identifier: [{BRAND_COLOR}]{session_id}[/{BRAND_COLOR}]")
print_info(console, "Find your row at https://mem0.ai/agentrush")
-14
View File
@@ -51,20 +51,12 @@ class TelemetryConfig:
anonymous_id: str = ""
@dataclass
class AgentRushConfig:
# ISO timestamp the human acknowledged the "memories are public" warning.
# Empty until first interactive `mem0 agent-rush add`.
acknowledged_at: str = ""
@dataclass
class Mem0Config:
version: int = CONFIG_VERSION
defaults: DefaultsConfig = field(default_factory=DefaultsConfig)
platform: PlatformConfig = field(default_factory=PlatformConfig)
telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
agent_rush: AgentRushConfig = field(default_factory=AgentRushConfig)
SHORT_KEY_ALIASES: dict[str, str] = {
@@ -113,9 +105,6 @@ def load_config() -> Mem0Config:
telemetry = data.get("telemetry", {})
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
agent_rush = data.get("agent_rush", {})
config.agent_rush.acknowledged_at = agent_rush.get("acknowledged_at", "")
# Environment variable overrides
env_key = os.environ.get("MEM0_API_KEY")
if env_key:
@@ -169,9 +158,6 @@ def save_config(config: Mem0Config) -> None:
"telemetry": {
"anonymous_id": config.telemetry.anonymous_id,
},
"agent_rush": {
"acknowledged_at": config.agent_rush.acknowledged_at,
},
}
with open(CONFIG_FILE, "w") as f:
+3 -6
View File
@@ -32,13 +32,12 @@ def _run(args: list[str], home_dir: str | None = None) -> subprocess.CompletedPr
if key.startswith("MEM0_"):
del env[key]
env.pop("FORCE_COLOR", None)
env["PYTHONIOENCODING"] = "utf-8"
if home_dir:
env["HOME"] = home_dir
result = subprocess.run(
[sys.executable, "-m", "mem0_cli", *args],
capture_output=True,
encoding="utf-8",
text=True,
env=env,
timeout=15,
)
@@ -100,13 +99,12 @@ class TestArgvPreprocessing:
result = subprocess.run(
[sys.executable, "-m", "mem0_cli", "init", "--agent"],
capture_output=True,
encoding="utf-8",
text=True,
env={
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
"HOME": clean_home,
"MEM0_BASE_URL": "http://127.0.0.1:1", # blackhole
"FORCE_COLOR": "0",
"PYTHONIOENCODING": "utf-8",
},
timeout=15,
)
@@ -135,13 +133,12 @@ class TestJsonEnvelopeParity:
result = subprocess.run(
[sys.executable, "-m", "mem0_cli", "init", "--agent", "--json"],
capture_output=True,
encoding="utf-8",
text=True,
env={
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
"HOME": clean_home,
"MEM0_BASE_URL": "http://127.0.0.1:1",
"FORCE_COLOR": "0",
"PYTHONIOENCODING": "utf-8",
},
timeout=15,
)
+1 -2
View File
@@ -49,7 +49,6 @@ def _run(
if key.startswith("MEM0_"):
del env[key]
env.pop("FORCE_COLOR", None)
env["PYTHONIOENCODING"] = "utf-8"
if home_dir:
env["HOME"] = home_dir
if env_override:
@@ -57,7 +56,7 @@ def _run(
result = subprocess.run(
[sys.executable, "-m", "mem0_cli", *args],
capture_output=True,
encoding="utf-8",
text=True,
env=env,
)
return subprocess.CompletedProcess(
+7 -7
View File
@@ -8,8 +8,8 @@ from io import StringIO
from unittest.mock import patch
import pytest
from click.exceptions import Exit as ClickExit
from rich.console import Console
from typer import Exit as TyperExit
from mem0_cli.commands.config_cmd import (
cmd_config_get,
@@ -181,7 +181,7 @@ class TestAddCommand:
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_add(
mock_backend,
@@ -206,7 +206,7 @@ class TestAddCommand:
with (
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_add(
mock_backend,
@@ -764,7 +764,7 @@ class TestImportCommand:
with (
patch("mem0_cli.commands.utils.console", console),
patch("mem0_cli.commands.utils.err_console", err_console),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None)
@@ -801,7 +801,7 @@ class TestEntitiesListCommand:
with (
patch("mem0_cli.commands.entities.console", console),
patch("mem0_cli.commands.entities.err_console", err_console),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_entities_list(mock_backend, "invalid", output="table")
@@ -944,7 +944,7 @@ class TestEntitiesDeleteCommand:
with (
patch("mem0_cli.commands.entities.console", console),
patch("mem0_cli.commands.entities.err_console", err_console),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_entities_delete(
mock_backend,
@@ -1308,7 +1308,7 @@ class TestAgentMode:
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
patch("sys.stdout", captured_stdout),
pytest.raises((SystemExit, TyperExit)),
pytest.raises((SystemExit, ClickExit)),
):
cmd_get(mock_backend, "bad-id", output="text")
+1 -2
View File
@@ -67,8 +67,7 @@ class TestConfig:
from mem0_cli.config import CONFIG_FILE
mode = os.stat(CONFIG_FILE).st_mode & 0o777
if os.name != "nt":
assert mode == 0o600
assert mode == 0o600
def test_defaults_save_and_load(self, isolate_config):
config = Mem0Config()
@@ -555,7 +555,7 @@
"# - Enables creation of AI agents with long-term memory and learning abilities.\n",
"# - Improves consistency and reduces repetition in user-agent interactions.\n",
"\n",
"from helper.mem0_teachability import Mem0Teachability\n",
"from cookbooks.helper.mem0_teachability import Mem0Teachability\n",
"\n",
"teachability = Mem0Teachability(\n",
" verbosity=2, # for visibility of what's happening\n",
@@ -79,7 +79,7 @@ new_project = client.project.create(
### Update Project Settings
Modify project configuration including custom instructions, categories, and language preferences:
Modify project configuration including custom instructions, categories, graph settings, and language preferences:
```python
# Update project with custom categories
+2 -2
View File
@@ -46,9 +46,9 @@ Ground-up rewrite of the memory pipeline with 20+ point benchmark improvements:
- **~3-4x fewer tokens** — Under 7K tokens per retrieval vs 25K+ for full-context approaches
- **ADD-only extraction** — Memories accumulate; nothing is overwritten or deleted
- **Hybrid retrieval** — Semantic + BM25 keyword + entity boost, scored in parallel
- **Graph memory (built-in)**: entities extracted, embedded, and linked across memories, with no external graph store required
- **Entity linking** — Entities extracted, embedded, and linked across memories
Breaking changes: external graph stores removed from OSS (replaced by built-in graph memory), `search()` defaults changed, deprecated params removed. See [migration guide](/migration/oss-v2-to-v3).
Breaking changes: Graph memory removed from OSS, `search()` defaults changed, deprecated params removed. See [migration guide](/migration/oss-v2-to-v3).
</Update>
-33
View File
@@ -4,39 +4,6 @@ description: "Release notes for the OpenClaw plugin and agent harness."
mode: "wide"
---
<Update label="2026-06-12" description="v1.0.13">
**Fixes:**
- **Custom categories payload:** `customCategories` (a `Record<string, string>` map) is now converted via the new `customCategoryMapToList()` helper into the `Array<Record<string, string>>` shape the Mem0 SDK expects on `add` calls — previously the raw object was passed as `custom_categories` and silently ignored ([#5345](https://github.com/mem0ai/mem0/pull/5345))
- **Skip runtime setup during metadata registration:** `register()` now detects `registrationMode === "cli-metadata"`, registers only the CLI commands, and returns early — avoiding backend initialization, service/tool registration, and hook installation during OpenClaw's metadata-only registration pass ([#5383](https://github.com/mem0ai/mem0/pull/5383))
**Security:**
- Bumped `mem0ai` from `3.0.3` to `3.0.7` (latest Node SDK) — includes the transitive axios CVE remediation shipped in `3.0.6` ([#5460](https://github.com/mem0ai/mem0/pull/5460))
- Added pnpm override `uuid@<11.1.1` → `>=11.1.1` to resolve an open MEDIUM Dependabot alert ([#5489](https://github.com/mem0ai/mem0/pull/5489))
**Improvements:**
- **Repo consolidation:** Plugin moved from repo-root `openclaw/` to `integrations/openclaw/`; `package.json` `repository.directory` updated to match so npm provenance links to the correct subdirectory ([#5491](https://github.com/mem0ai/mem0/pull/5491))
**Tests:**
- Added `customCategoryMapToList` unit tests and a `PlatformProvider` test asserting `custom_categories` is passed to the Mem0 SDK as a list ([#5345](https://github.com/mem0ai/mem0/pull/5345))
- Added a regression test asserting `cli-metadata` registration registers only CLI commands and triggers no runtime side effects ([#5383](https://github.com/mem0ai/mem0/pull/5383))
</Update>
<Update label="2026-06-02" description="v1.0.12">
**Docs:**
- **Agent Mode onboarding:** README now documents an autonomous setup path for AI agents — `mem0 init --agent --json` mints an evaluation Mem0 API key with no email, OTP, or browser and exports it as `MEM0_API_KEY` for `openclaw mem0 init`; a human owner can later run `mem0 init --email <email>` to claim ownership without disrupting the agent ([#5123](https://github.com/mem0ai/mem0/pull/5123))
**Security:**
- Added pnpm overrides to remediate advisories in transitive dependencies: `langsmith@<0.6.0` → `^0.6.0`, `picomatch@<2.3.2` → `^2.3.2`, `vite` → `^8.0.5`, and `@qdrant/js-client-rest` → `^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
**Dependencies:**
- Bumped `mem0ai` from `3.0.2` to `3.0.3` ([#5212](https://github.com/mem0ai/mem0/pull/5212))
- Bumped dev dependencies `@vitest/coverage-v8` and `vitest` from `^4.0.18` to `^4.1.7`; added `vite@^8.0.5` and `@qdrant/js-client-rest@^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
</Update>
<Update label="2026-04-29" description="v1.0.11">
**New Features:**
+1 -1
View File
@@ -25,7 +25,7 @@ mode: "wide"
<Update label="2026-04-16" description="">
**Improvements:**
- **UI:** Removed the legacy external-graph-store visualization tab, page, and its references from dashboard, sidebar, project settings, playground, and billing
- **UI:** Removed Graph Memory tab, page, and all references from dashboard, sidebar, project settings, playground, and billing
</Update>
+4 -199
View File
@@ -7,92 +7,6 @@ mode: "wide"
<Tabs>
<Tab title="Python">
<Update label="2026-06-17" description="v2.0.7">
**New Features:**
- **LLMs:** Add Gemini via Vertex AI as LLM provider ([#4030](https://github.com/mem0ai/mem0/pull/4030))
- **Embeddings:** Add native `embed_batch` to `OllamaEmbedding` for batched embedding requests ([#5415](https://github.com/mem0ai/mem0/pull/5415))
**Bug Fixes:**
- **Core:** Fix `api_error_handler` silently dropping return values from async methods ([#5540](https://github.com/mem0ai/mem0/pull/5540))
- **Core:** Fix `AsyncMemory.reset()` not resetting the entity store ([#5535](https://github.com/mem0ai/mem0/pull/5535))
- **Core:** Fix `async delete_all` aborting on first error, leaving partial deletion ([#5529](https://github.com/mem0ai/mem0/pull/5529))
- **Core:** Skip messages without a `content` key in message parsers to prevent `KeyError` crashes ([#5575](https://github.com/mem0ai/mem0/pull/5575))
- **Core:** Preserve custom metadata fields during memory update ([#5480](https://github.com/mem0ai/mem0/pull/5480))
- **LLMs:** Fix Anthropic `tool_choice` format and tool response parsing ([#5537](https://github.com/mem0ai/mem0/pull/5537))
- **LLMs:** Fix Ollama `json` format mutating the caller's messages list in-place ([#5539](https://github.com/mem0ai/mem0/pull/5539))
- **LLMs:** Omit `None` config values from Gemini `GenerateContentConfig` to prevent validation errors ([#5528](https://github.com/mem0ai/mem0/pull/5528))
- **LLMs:** Honor reasoning-model params in `AzureOpenAIStructuredLLM` ([#5548](https://github.com/mem0ai/mem0/pull/5548))
- **LLMs:** Honor reasoning-model params in `OpenAIStructuredLLM` ([#5458](https://github.com/mem0ai/mem0/pull/5458))
- **LLMs:** Send `max_completion_tokens` for the GPT-5 family across all providers ([#5547](https://github.com/mem0ai/mem0/pull/5547))
- **LLMs:** Accept and forward `**kwargs` in Together, LangChain, and Sarvam providers ([#5556](https://github.com/mem0ai/mem0/pull/5556))
- **LLMs:** Fix Bedrock AI21 response parse default using `dict` literal instead of `set` ([#5527](https://github.com/mem0ai/mem0/pull/5527))
- **LLMs:** Fix LiteLLM function-calling check blocking all calls on non-tool models ([#5536](https://github.com/mem0ai/mem0/pull/5536))
- **LLMs:** Fix HuggingFace provider using `self.config` instead of raw `config` parameter ([#5538](https://github.com/mem0ai/mem0/pull/5538))
- **Embeddings:** Honor `aws_session_token` in AWS Bedrock embeddings ([#5566](https://github.com/mem0ai/mem0/pull/5566))
- **Rerankers:** Respect `config.top_k` in Cohere and ZeroEntropy fallback paths ([#5560](https://github.com/mem0ai/mem0/pull/5560))
- **Vector Stores:** Fix FAISS filtered search dropping over-fetched candidates before filtering ([#5453](https://github.com/mem0ai/mem0/pull/5453))
- **Vector Stores:** Fix Weaviate `reset()` crashing with missing `vector_size` argument ([#5531](https://github.com/mem0ai/mem0/pull/5531))
- **Vector Stores:** Pass embedding dims in Weaviate `reset()` to avoid re-init crash ([#5570](https://github.com/mem0ai/mem0/pull/5570))
- **Vector Stores:** Fix MongoDB `reset()` passing wrong argument to `create_col()` ([#5532](https://github.com/mem0ai/mem0/pull/5532))
- **Vector Stores:** Fix Pinecone hybrid search crashing when `filters` is `None` ([#5533](https://github.com/mem0ai/mem0/pull/5533))
- **Vector Stores:** Fix Redis crashing on empty or `None` filters in `search()` and `list()` ([#5446](https://github.com/mem0ai/mem0/pull/5446))
- **Vector Stores:** Return `None` from `get()` for missing IDs in Milvus, Weaviate, and Supabase ([#5562](https://github.com/mem0ai/mem0/pull/5562))
- **Vector Stores:** Return `None` from ChromaDB `get()` for missing IDs ([#5561](https://github.com/mem0ai/mem0/pull/5561))
</Update>
<Update label="2026-06-13" description="v2.0.6">
**New Features:**
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
**Bug Fixes:**
- **Memory:** Prevent a crash in `parse_vision_messages` when vision support is disabled ([#5487](https://github.com/mem0ai/mem0/pull/5487))
- **Vector Stores:** Expose the `https` option on the Qdrant vector store configuration so TLS endpoints can be targeted explicitly ([#5380](https://github.com/mem0ai/mem0/pull/5380))
- **Vector Stores:** Use valid S3 Vectors entity index names, fixing index operations that failed on invalid names ([#5416](https://github.com/mem0ai/mem0/pull/5416))
- **Vector Stores:** Fix `search()` crashing with a `TypeError` in the LangChain vector store when a result score is `None` ([#5072](https://github.com/mem0ai/mem0/pull/5072))
- **Vector Stores:** Use `is not None` instead of a truthiness check for vector/payload in the PGVector `update()` path, so valid empty/zero values are no longer skipped ([#5488](https://github.com/mem0ai/mem0/pull/5488))
- **Vector Stores:** Index the Valkey `memory` field as `TEXT` rather than `TAG` so full-text search behaves correctly ([#5443](https://github.com/mem0ai/mem0/pull/5443))
- **Vector Stores:** Implement `$not` filter support in the ChromaDB vector store ([#5485](https://github.com/mem0ai/mem0/pull/5485))
</Update>
<Update label="2026-06-10" description="v2.0.5">
**New Features:**
- **Memory:** Warn at init time when hybrid/BM25 search silently degrades to semantic-only because the configured vector store does not implement `keyword_search`. Affected stores: Chroma, FAISS, Cassandra, LangChain, Neptune Analytics, S3 Vectors, Supabase, TurboPuffer, Valkey ([#5444](https://github.com/mem0ai/mem0/pull/5444))
- **Memory:** Add opt-in `explain=True` parameter to `Memory.search()` and `AsyncMemory.search()`. When enabled, each result includes a `score_breakdown` dict with `semantic`, `keyword` (normalized BM25), `entity_boost`, and `temporal_boost` signals so callers can understand and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
**Bug Fixes:**
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) consistently across all backends. 11 adapters previously returned raw distance metrics (lower = better) — FAISS, Chroma, Milvus, Redis, Cassandra, PGVector, S3 Vectors, Supabase, Valkey, Azure MySQL, and Vertex AI Vector Search — causing incorrect ranking in multi-store setups ([#5391](https://github.com/mem0ai/mem0/pull/5391))
- **Memory:** Parallelize entity boost searches in `Memory.search()` and `AsyncMemory.search()`. Previously up to 8 entities were embedded and queried sequentially (16 serial round-trips with remote embedders); all entity lookups now run concurrently, eliminating multi-second latency on entity-rich queries ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Memory:** Reject empty or whitespace-only queries in `Memory.search()`, `AsyncMemory.search()`, `MemoryClient.search()`, and `AsyncMemoryClient.search()` before any embedding or API call is made. Also strips leading/trailing whitespace from valid queries ([#5258](https://github.com/mem0ai/mem0/pull/5258))
- **LLMs:** Add `is_reasoning_model: Optional[bool]` override to `BaseLlmConfig` (surfaced on `OpenAILlmConfig` and `AzureOpenAILlmConfig`). Fixes silent zero-extraction when using Azure deployments with versioned `gpt-5.x` names that the automatic name-based heuristic cannot recognize ([#5327](https://github.com/mem0ai/mem0/pull/5327))
- **LLMs:** Fix xAI LLM provider: add `XAIConfig` with `xai_base_url`, forward `tools`/`tool_choice` in `generate_response()`, and parse `tool_calls` in the response. Previously the provider raised `AttributeError` at init and silently dropped tool results ([#5190](https://github.com/mem0ai/mem0/pull/5190))
- **Vector Stores:** Fix PGVector `ConnectionPool` hang in Docker Compose environments where the app container starts before Postgres is DNS-resolvable — switched to `open=False` to avoid blocking constructor or silent zombie pool ([#5155](https://github.com/mem0ai/mem0/pull/5155))
- **Vector Stores:** Fix PGVector `sslmode` handling for PostgreSQL URIs — the `sslmode` query parameter is now correctly extracted and forwarded when building the async connection pool ([#5308](https://github.com/mem0ai/mem0/pull/5308))
- **Vector Stores:** Fix S3 Vectors `list()` not applying metadata filters — filtering is now done client-side after fetching, with pagination preserved and `top_k` applied after filtering to prevent pre-truncation of matching rows ([#5018](https://github.com/mem0ai/mem0/pull/5018))
- **Vector Stores:** Fix Upstash Vector `search()` routing all queries to the default namespace — `namespace` is now passed as a top-level keyword argument to `query_many()` instead of inside the per-query dict where it was silently ignored ([#5202](https://github.com/mem0ai/mem0/pull/5202))
- **Core:** Replace mutable default arguments with `None` sentinels in embedder configs and the proxy module, preventing cross-request state contamination ([#5302](https://github.com/mem0ai/mem0/pull/5302))
</Update>
<Update label="2026-05-27" description="v2.0.4">
**New Features:**
- **Client:** `delete()` and async `delete()` accept `delete_linked` (default `False`). When `True`, deleting a memory also removes the older memories it superseded (the v3 `linked_memory_ids` chain), transitively — the delete-side counterpart of `latest_only`, so a superseded memory does not resurface after the current one is deleted ([#5270](https://github.com/mem0ai/mem0/pull/5270))
</Update>
<Update label="2026-05-26" description="v2.0.3">
**Bug Fixes:**
- **Vector Stores:** PGVector adapter now supports rich filter operators (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `icontains`, wildcard `*`, `$or`, `$not`) in `search()`, `keyword_search()`, and `list()`. Previously only exact-equality filters worked — operator dicts were silently stringified and returned zero results ([#5263](https://github.com/mem0ai/mem0/pull/5263))
- **Server:** Fixed `/search` endpoint returning 502 when `user_id`, `agent_id`, or `run_id` are sent as top-level request fields. The server now maps these into the `filters` dict before calling `Memory.search()`, matching the v3 API contract. Top-level entity ID fields are marked as deprecated in the OpenAPI schema and emit a warning log — clients should migrate to `filters={"user_id": "..."}` ([#5263](https://github.com/mem0ai/mem0/pull/5263))
</Update>
<Update label="2026-05-08" description="v2.0.2">
**Bug Fixes:**
@@ -149,8 +63,8 @@ mode: "wide"
- **`messages` in `Memory.add()` rejects invalid types:** Passing `None` or non-`(str | dict | list)` values raises `Mem0ValidationError` (`error_code="VALIDATION_003"`) ([#4843](https://github.com/mem0ai/mem0/pull/4843))
- **`qdrant-client>=1.12.0` required** — Upgrade from `>=1.9.1` ([#4805](https://github.com/mem0ai/mem0/pull/4805))
- **`org_id` and `project_id` removed** — Removed from `MemoryClient` constructor and all method signatures ([#4740](https://github.com/mem0ai/mem0/pull/4740))
- **External Graph Store Removed (OSS):** `mem0/memory/graph_memory.py`, `memgraph_memory.py`, `kuzu_memory.py`, `apache_age_memory.py`, and `mem0/graphs/` (Neo4j / Memgraph / Kuzu / Apache AGE / Neptune drivers) deleted, about 4,000 lines. The external graph store integration is no longer part of the OSS SDK; graph drivers (neo4j, memgraph, kuzu, etc.) can be uninstalled. Graph memory now runs natively as built-in entity linking. Remove `enable_graph` and `graph_store` from your config ([#4805](https://github.com/mem0ai/mem0/pull/4805))
- **`enable_graph` removed from Client SDK:** Graph memory now runs automatically and no longer needs a flag. Remove `enable_graph` from `MemoryClient.add()` / `search()` / `get_all()` / `update_project()` calls ([#4776](https://github.com/mem0ai/mem0/pull/4776))
- **Graph Memory Removed (OSS):** `mem0/memory/graph_memory.py`, `memgraph_memory.py`, `kuzu_memory.py`, `apache_age_memory.py`, and `mem0/graphs/` (Neo4j / Memgraph / Kuzu / Apache AGE / Neptune drivers) deleted — ~4,000 lines. Graph memory is no longer supported in the OSS SDK; graph drivers (neo4j, memgraph, kuzu, etc.) can be uninstalled. Use the Platform API for graph features. Remove `enable_graph` and `graph_store` from your config ([#4805](https://github.com/mem0ai/mem0/pull/4805))
- **`enable_graph` removed from Client SDK** — Graph memory is now a project-level setting on the Platform. Remove `enable_graph` from `MemoryClient.add()` / `search()` / `get_all()` / `update_project()` calls ([#4776](https://github.com/mem0ai/mem0/pull/4776))
- **`custom_fact_extraction_prompt` renamed to `custom_instructions`** — Update config and memory module references ([#4740](https://github.com/mem0ai/mem0/pull/4740))
- **Typed option classes** — Added Pydantic v2 typed classes: `AddMemoryOptions`, `SearchMemoryOptions`, `GetAllMemoryOptions`, `DeleteAllMemoryOptions`, `UpdateMemoryOptions`, `ProjectUpdateOptions` ([#4740](https://github.com/mem0ai/mem0/pull/4740))
@@ -1010,64 +924,6 @@ See the [OSS v1 to v2 migration guide](https://docs.mem0.ai/migration/oss-v1-to-
</Tab>
<Tab title="TypeScript">
<Update label="2026-06-17" description="v3.0.9">
**Bug Fixes:**
- **LLMs:** Fix Anthropic `tool_choice` format — was incorrectly sent as a bare string `"auto"` (rejected by the API); now correctly sent as `{ type: "auto" }`. Also fixes tool response parsing: `tool_use` blocks are now parsed into `toolCalls` objects instead of throwing. Updated default model to `claude-sonnet-4-6` and default `max_tokens` to `2000` to match the Python provider. Added `temperature`, `topP`, and `maxTokens` to `LLMConfig` so Anthropic params can be configured ([#5537](https://github.com/mem0ai/mem0/pull/5537))
- **Memory (OSS):** Preserve custom metadata fields during `update()` — fields such as `category`, `priority`, and other user-defined keys were previously dropped on update; the existing payload is now spread before applying the new data ([#5480](https://github.com/mem0ai/mem0/pull/5480))
- **Client:** Preserve user-defined schema keys in `createMemoryExport` ([#5594](https://github.com/mem0ai/mem0/pull/5594))
**Security:**
- **Dependencies:** Bump `esbuild` to `>=0.28.1` across all npm packages via pnpm overrides to remediate upstream vulnerability ([#5563](https://github.com/mem0ai/mem0/pull/5563))
</Update>
<Update label="2026-06-13" description="v3.0.8">
**New Features:**
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
**Security:**
- **Dependencies:** Upgrade `@langchain/community` to `^1.1.18` to remediate CVE-2026-27795 and CVE-2026-26019 ([#5510](https://github.com/mem0ai/mem0/pull/5510))
- **Dependencies:** Resolve all open MEDIUM Dependabot alerts via pnpm overrides ([#5489](https://github.com/mem0ai/mem0/pull/5489))
</Update>
<Update label="2026-06-10" description="v3.0.7">
**New Features:**
- **Embeddings:** Add `LMStudioEmbedding` provider for local embeddings via the LM Studio server ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Memory:** Add opt-in `explain: true` option to `Memory.search()`. When enabled, each result includes a `scoreBreakdown` object with `semantic`, `keyword`, `entityBoost`, and `temporalBoost` fields so callers can inspect and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
**Bug Fixes:**
- **Memory:** Parallelize entity boost searches in `Memory.search()`. All entity embed + store lookups now run concurrently instead of sequentially, eliminating multi-second latency on entity-rich queries with remote embedding providers ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) — fixed score inversion in the Redis vector store adapter ([#5391](https://github.com/mem0ai/mem0/pull/5391))
- **Embeddings:** Request `encoding_format: "float"` from the OpenAI embedder in both `embed()` and `embedBatch()`. Fixes incorrect vector dimensions when using OpenAI-compatible proxies that default to base64 encoding ([#5170](https://github.com/mem0ai/mem0/pull/5170))
</Update>
<Update label="2026-06-01" description="v3.0.6">
**Security:**
- **Dependencies:** Bumped `axios` to `^1.16.0` to remediate high-severity prototype-pollution CVEs (credential theft, MITM, DoS). Pinned transitive dependencies via pnpm overrides: `jws` → 4.0.1 (CVE-2025-65945), `langsmith` → ^0.6.0 (CVE-2026-45134), `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343), `picomatch` → ^2.3.2 (CVE-2026-33671), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `path-to-regexp` → ^8.4.0 (CVE-2026-4926), `rollup` → ^4.59.0 (CVE-2026-27606), `glob` → ^10.5.0 (CVE-2025-64756), `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
</Update>
<Update label="2026-05-27" description="v3.0.5">
**New Features:**
- **Client:** `delete()` accepts an options object with `deleteLinked` (serialized as `delete_linked`, default `false`). When `true`, deleting a memory also removes the older memories it superseded (the v3 linked chain), transitively — the delete-side counterpart of `latestOnly`, so a superseded memory does not resurface after the current one is deleted ([#5270](https://github.com/mem0ai/mem0/pull/5270))
</Update>
<Update label="2026-05-26" description="v3.0.4">
**Bug Fixes:**
- **Vector Stores:** PGVector adapter now supports rich filter operators (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `icontains`, wildcard `*`, `$or`, `$not`) in `search()`, `keywordSearch()`, and `list()`. Previously only exact-equality filters worked — operator objects were passed as raw values and returned incorrect results ([#5263](https://github.com/mem0ai/mem0/pull/5263))
</Update>
<Update label="2026-05-08" description="v3.0.3">
**Bug Fixes:**
@@ -1113,7 +969,7 @@ See the [OSS v1 to v2 migration guide](https://docs.mem0.ai/migration/oss-v1-to-
- **Default model:** `gpt-5-mini` is now the default in `OpenAI`, `OpenAIStructured`, and `Azure` LLM providers ([#4829](https://github.com/mem0ai/mem0/pull/4829))
**Breaking Changes:**
- **External Graph Store Removed (OSS):** `graph_memory.ts` (675 lines), `graphs/tools.ts` (267 lines), `graphs/utils.ts` (116 lines), `graphs/configs.ts` (30 lines) deleted. The external graph store integration is no longer part of the OSS SDK; graph memory now runs natively as built-in entity linking ([#4805](https://github.com/mem0ai/mem0/pull/4805))
- **Graph Memory Removed (OSS):** `graph_memory.ts` (675 lines), `graphs/tools.ts` (267 lines), `graphs/utils.ts` (116 lines), `graphs/configs.ts` (30 lines) deleted. Graph memory is no longer supported in the OSS SDK — use Platform API for graph features ([#4805](https://github.com/mem0ai/mem0/pull/4805))
- **camelCase Parameters (Client SDK):** All user-facing parameters converted from snake_case to camelCase. Mapping is transparent at API boundary via `camelToSnakeKeys()` / `snakeToCamelKeys()` ([#4776](https://github.com/mem0ai/mem0/pull/4776))
```typescript
// Before
@@ -1467,24 +1323,10 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
<Tab title="CLI">
<Update label="2026-06-01" description="Node v0.2.8">
**Security:**
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `jws` → 4.0.1 (CVE-2025-65945), `langsmith` → ^0.6.0 (CVE-2026-45134), `tar-fs` → ^2.1.4 (CVE-2025-48387, CVE-2025-59343), `picomatch` → ^2.3.2 (CVE-2026-33671), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `path-to-regexp` → ^8.4.0 (CVE-2026-4926), `rollup` → ^4.59.0 (CVE-2026-27606), `glob` → ^10.5.0 (CVE-2025-64756), `@modelcontextprotocol/sdk` → ^1.25.4 (CVE-2025-66414, CVE-2026-0621)
</Update>
<Update label="2026-05-16" description="Python v0.2.6 / Node v0.2.6">
**Bug Fixes:**
- **Claim flow error message:** The `email_already_claimed` tip in `mem0 init --email` previously suggested running `mem0 link <key>` — a command that doesn't exist. Replaced with honest copy pointing the user to sign in at app.mem0.ai with their existing credentials ([#5152](https://github.com/mem0ai/mem0/pull/5152))
</Update>
<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))
@@ -1590,43 +1432,6 @@ A full-featured command-line interface for Mem0, available in both Python and No
<Tab title="Plugins">
<Update label="2026-06-01" description="openclaw-mem0 v1.0.12">
**Security:**
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `protobufjs` → ^7.5.5, `vite` → ^8.0.5, `langsmith` → ^0.6.0 (CVE-2026-45134), `picomatch` → ^2.3.2 (CVE-2026-33671), `@qdrant/js-client-rest` → ^1.18.0
</Update>
<Update label="2026-06-10" description="Vercel AI SDK v3.0.0">
**Major Release** — Migrated to Vercel AI SDK v6 (`LanguageModelV3` / `ProviderV3`) and Mem0 v3 API.
**Breaking Changes:**
- **AI SDK v6:** Upgraded from AI SDK v5 (`LanguageModelV2`) to v6 (`LanguageModelV3`). Users must upgrade `ai` to `^6.0.199` and all `@ai-sdk/*` provider packages to `^3.x` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Mem0 v3 API:** Memory endpoints migrated from `/v1/memories/` and `/v2/memories/search/` to `/v3/memories/add/` and `/v3/memories/search/`. Entity IDs (`user_id`, `agent_id`, `run_id`) now go inside the `filters` object for search requests ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Graph memory removed:** All `enable_graph`, graph prompts, and relation-extraction code removed. Graph memory is now a project-level setting on the Platform ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Deprecated params removed:** `org_id`, `project_id`, `org_name`, `project_name`, `output_format`, `filter_memories`, `async_mode`, `enable_graph`, `version`, `api_version` removed from `Mem0ConfigSettings` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
**New Features:**
- **V3 provider contract:** `specificationVersion: 'v3'`, `supportedUrls` property, V3 content array in `doGenerate`, V3 stream lifecycle events in `doStream` ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Mem0 source in responses:** Memories are attached as a `source` in `generateText`/`streamText` responses with `providerMetadata.mem0.memories` for programmatic access ([#4741](https://github.com/mem0ai/mem0/pull/4741))
**Bug Fixes:**
- **Async memory storage:** `addMemories` is now properly `await`ed — memories no longer silently fail to store ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Prompt mutation:** Prompt array is now cloned before injecting memory context, preventing side effects on the caller's array ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Null guard on content:** `doGenerate` guards against null `content` from upstream providers ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Stream response:** `doStream` now returns the full `LanguageModelV3StreamResult` object preserving all V3 fields ([#4741](https://github.com/mem0ai/mem0/pull/4741))
- **Response normalization:** `getMemories` and `retrieveMemories` now handle both array and `{results: [...]}` envelope responses from the v3 API ([#4741](https://github.com/mem0ai/mem0/pull/4741))
</Update>
<Update label="2026-06-01" description="Vercel AI SDK v2.0.6">
**Security:**
- **Dependencies:** Pinned transitive dependencies via pnpm overrides to remediate high-severity CVEs: `glob` → ^10.5.0 (CVE-2025-64756), `minimatch` → ^3.1.3 / ^5.1.8 / ^9.0.7 (CVE-2026-27903, CVE-2026-27904, CVE-2026-26996), `picomatch` → ^2.3.2 (CVE-2026-33671), `rollup` → ^4.59.0 (CVE-2026-27606)
</Update>
<Update label="2026-04-02" description="mem0-plugin v1.0.0">
**Mem0 Plugin for Claude Code, Cursor, and Codex**
-156
View File
@@ -1,156 +0,0 @@
---
title: "Neon"
description: "Use Neon as a vector store in Mem0, powered by PostgreSQL and pgvector."
---
Use [Neon](https://neon.com/) as a vector store in Mem0, powered by PostgreSQL and the
[pgvector extension](https://neon.com/docs/extensions/pgvector).
Neon is a serverless Postgres platform. Since Mem0 supports Postgres through the
`pgvector` provider, Neon can be used with a standard Postgres connection string.
## Usage
<CodeGroup>
```python Python
import os
from dotenv import load_dotenv
from mem0 import Memory
load_dotenv()
config = {
"vector_store": {
"provider": "pgvector",
"config": {
"connection_string": os.environ["DATABASE_URL"],
"collection_name": "memories",
"embedding_model_dims": 1536,
"hnsw": True,
},
},
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."},
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
results = m.search(
"What movies should I recommend?",
filters={"user_id": "alice"},
)
print(results)
```
```typescript TypeScript
import "dotenv/config";
import { Memory } from "mem0ai/oss";
const databaseUrl = new URL(process.env.DATABASE_URL!);
const m = new Memory({
vectorStore: {
provider: "pgvector",
config: {
user: decodeURIComponent(databaseUrl.username),
password: decodeURIComponent(databaseUrl.password),
host: databaseUrl.hostname,
port: Number(databaseUrl.port || 5432),
dbname: databaseUrl.pathname.slice(1) || "neondb",
collectionName: "memories",
dimension: 1536,
embeddingModelDims: 1536,
hnsw: true,
},
},
});
const messages = [
{ role: "user" as const, content: "I'm planning to watch a movie tonight. Any recommendations?" },
{ role: "assistant" as const, content: "How about thriller movies? They can be quite engaging." },
{ role: "user" as const, content: "I'm not a big fan of thriller movies but I love sci-fi movies." },
{ role: "assistant" as const, content: "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future." },
];
await m.add(messages, {
userId: "alice",
metadata: { category: "movies" },
});
const results = await m.search("What movies should I recommend?", {
filters: { user_id: "alice" },
});
console.log(results);
```
</CodeGroup>
## SQL Migration
You don't need to run any SQL migrations. Mem0 creates the collection table when it initializes the `pgvector` store.
## Environment
```env
OPENAI_API_KEY=sk-xx...
DATABASE_URL=postgresql://user:password@ep-example.us-east-2.aws.neon.tech/neondb?sslmode=require
```
## Config
<Tabs>
<Tab title="Python">
| Parameter | Description | Default Value |
| --- | --- | --- |
| `connection_string` | Neon Postgres connection string. | Required |
| `collection_name` | Name for the vector collection. | `mem0` |
| `embedding_model_dims` | Embedding model dimensions. | `1536` |
| `hnsw` | Enables HNSW indexing. | `False` |
| `sslmode` | PostgreSQL SSL mode. Use `require` for Neon. | Driver default |
</Tab>
<Tab title="TypeScript">
The current Mem0 TypeScript `pgvector` adapter takes individual Postgres fields,
so parse `DATABASE_URL` before creating `Memory`.
| Parameter | Description | Default |
| --- | --- | --- |
| `user` | Database user. | Required |
| `password` | Database password. | Required |
| `host` | Database host. | Required |
| `port` | Database port. | `5432` |
| `dbname` | Database name. | `vector_store` |
| `collectionName` | Name for the vector collection. | `memories` |
| `dimension` | Vector dimension for Mem0 config. | Auto-detected |
| `embeddingModelDims` | Embedding model dimensions for table creation. | Required |
| `hnsw` | Enables HNSW indexing. | `false` |
</Tab>
</Tabs>
### Indexing
The `pgvector` provider can create an HNSW index for faster vector search.
- Set `hnsw` to `true` to enable a Hierarchical Navigable Small World index.
- Leave `hnsw` as `false` if you want to create or manage indexes yourself.
### Similarity Search
The `pgvector` provider uses cosine similarity for vector search. Make sure your
embedding dimensions match the configured `embedding_model_dims` value.
### Best Practices
1. **Index Selection**:
- Use `hnsw` for faster search performance when memory usage is not a constraint
- Manage indexes manually if you need a different pgvector index strategy
2. **Connection String**:
- Always use environment variables or even better, a secret manager for sensitive information in the connection string
- Format: `postgresql://user:password@host:port/database`
+1 -2
View File
@@ -76,7 +76,6 @@ Let's see the available parameters for the `qdrant` config:
| `path` | Path for the qdrant database | `/tmp/qdrant` |
| `url` | Full URL for the qdrant server | `None` |
| `api_key` | API key for the qdrant server | `None` |
| `https` | Whether to force HTTPS on or off. `None` lets the client decide; set `False` for plain HTTP Qdrant with API key authentication. | `None` |
| `on_disk` | For enabling persistent storage | `False` |
</Tab>
<Tab title="TypeScript">
@@ -91,4 +90,4 @@ Let's see the available parameters for the `qdrant` config:
| `apiKey` | API key for the Qdrant server | `None` |
| `onDisk` | For enabling persistent storage | `False` |
</Tab>
</Tabs>
</Tabs>
@@ -323,6 +323,10 @@ Metadata: {'verified': True, 'updated_date': '2025-04-02'}
That “no duplicates” promise comes from the inference pipeline. Keep `infer=True` when you rely on automatic updates. Raw imports (`infer=False`) skip conflict checks, so mixing the two modes for the same fact will create duplicates.
</Warning>
**Maintains relationships:**
- If using graph memory, connections to other entities persist
### Pick the right inference mode
| Mode | What it does | Best for | Watch out for |
@@ -216,6 +216,7 @@ This information was retrieved from your memory history where you previously men
- **Smart Memory Management** - Organizes memories into searchable information *without setting up vector databases*
- **Fast Retrieval** - Instant lookups with *sub-millisecond ping*, handles large datasets
- **Graph Capabilities** - Builds knowledge *automatically* as you push information
- **Simple Integration** - Uses Mem0 API in the backend, works with *any MCP client* with just a few lines of code
### Gemini 3 + Mem0 Benefits
+8 -1
View File
@@ -156,7 +156,14 @@ Here are some examples of how Mem0 can be integrated into various applications:
icon="aws"
href="/cookbooks/integrations/aws-bedrock"
>
Mem0 with AWS Bedrock.
Mem0 with AWS Bedrock and Neptune.
</Card>
<Card
title="Graph Memory on Neptune"
icon="network-wired"
href="/cookbooks/integrations/neptune-analytics"
>
Graph memory with Neptune Analytics.
</Card>
</CardGroup>
+5 -5
View File
@@ -17,7 +17,7 @@ Some benchmarks today — particularly smaller ones like LoCoMo and LongMemEval
## Architecture Overview
Mem0's memory system operates across two phases, **extraction** (writing) and **retrieval** (reading), with a graph memory layer (entity linking) connecting them.
Mem0's memory system operates across two phases — **extraction** (writing) and **retrieval** (reading) — with an entity linking layer connecting them.
### Memory Extraction (Distillation)
@@ -27,14 +27,14 @@ When new conversations arrive, the extraction pipeline processes them through fi
2. **Context Lookup** — Find related existing memories to avoid duplicates
3. **Distill Memories** — Single-pass LLM extraction produces ADD-only facts from input + context
4. **Deduplicate + Embed** — Hash-based deduplication, then vectorize new memories
5. **Graph Memory (Entity Linking)**: Identify entities (proper nouns, quoted text, compound noun phrases) and link them across memories into a graph
5. **Entity Linking** — Identify entities (proper nouns, quoted text, compound noun phrases) and link them across memories
Memories are distributed across three storage layers, each tuned for a specific retrieval pattern:
| Store | Contents | Purpose |
|---|---|---|
| **Vector Database** | Memory text, embeddings, metadata (timestamps, hash, categories, attributed_to) | Primary fact storage + semantic retrieval |
| **Graph / Entity Store** | Entities + embeddings + linked memory IDs | Graph connections across memories + entity-based retrieval boost |
| **Entity Store** | Entities + embeddings + linked memory IDs | Entity-based retrieval boost |
| **SQL Database** | History log (ADD events) + rolling message window | Audit trail + extraction dedup context |
<Info>
@@ -47,7 +47,7 @@ When a query arrives, the retrieval pipeline scores candidates across three sign
1. **Semantic Search** — Vector similarity scoring against memory embeddings
2. **Keyword Search** — Normalized term matching via BM25 with verb-form lemmatization
3. **Entity Search** — Entity matching boosts memories linked to query entities
3. **Entity Search** — Entity graph matching boosts memories linked to query entities
Results are fused via rank scoring into a final top-K set. Different query types lean on different signals:
@@ -76,7 +76,7 @@ The combined score outperformed every individual signal across every category te
*Mean tokens: 6,956*
The two largest gains are **temporal queries (+29.6)** and **multi-hop reasoning (+23.1)**. Both categories directly test the ADD-only architecture (preserving temporal context) and graph memory / entity linking (connecting facts across memories).
The two largest gains are **temporal queries (+29.6)** and **multi-hop reasoning (+23.1)**. Both categories directly test the ADD-only architecture (preserving temporal context) and entity linking (connecting facts across memories).
### LongMemEval
+7 -3
View File
@@ -27,11 +27,15 @@ Adding memory is how Mem0 captures useful details from a conversation so your ag
Mem0 offers two flows:
- **Mem0 Platform** – Fully managed API with dashboard and scaling.
- **Mem0 Platform** – Fully managed API with dashboard, scaling, and graph features.
- **Mem0 Open Source** – Local SDK that you run in your own environment.
Both flows take the same payload and pass it through the same pipeline.
<Frame caption="Architecture diagram illustrating the process of adding memories.">
<img src="../../images/add_architecture.png" />
</Frame>
<Steps>
<Step title="Information extraction">
Mem0 sends the messages through an LLM that pulls out key facts, decisions, or preferences to remember.
@@ -40,7 +44,7 @@ Mem0 sends the messages through an LLM that pulls out key facts, decisions, or p
Existing memories are checked for duplicates or contradictions so the latest truth wins.
</Step>
<Step title="Storage">
The resulting memories land in managed vector storage so future searches return them quickly.
The resulting memories land in managed vector storage (and optional graph storage) so future searches return them quickly.
</Step>
</Steps>
@@ -173,7 +177,7 @@ For full list of supported fields, required formats, and advanced options, see t
## Put it into practice
- Review the <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> guide to layer metadata and rerankers.
- Review the <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> guide to layer metadata, rerankers, and graph toggles.
- Explore the <Link href="/api-reference/memory/add-memories">Add Memories API reference</Link> for every request/response field.
## See it live
@@ -25,6 +25,10 @@ Mem0's search operation lets agents ask natural-language questions and get back
## Architecture
<Frame caption="Architecture diagram illustrating the memory search process.">
<img src="../../images/search_architecture.png" />
</Frame>
<Steps>
<Step title="Query processing">
Mem0 cleans and enriches your natural-language query so the downstream embedding search is accurate.
@@ -156,33 +160,6 @@ const memories = memory.search("food preferences", {
On Mem0 Platform v3, time-aware queries use Temporal Reasoning internally while preserving the normal search response shape. See <Link href="/platform/features/temporal-reasoning">Temporal Reasoning</Link>.
</Note>
### Explain OSS search scores
OSS search combines semantic similarity with optional keyword and entity signals. Pass `explain=True` when tuning retrieval quality or debugging why a memory ranked where it did:
<CodeGroup>
```python Python
results = m.search(
"food preferences",
filters={"user_id": "alice"},
explain=True,
)
print(results["results"][0]["score_details"])
```
```javascript JavaScript
const results = await memory.search("food preferences", {
filters: { user_id: "alice" },
explain: true,
});
console.log(results.results[0].score_details);
```
</CodeGroup>
Each result includes `score_details` with the semantic score, normalized BM25 score, entity boost, raw combined score, maximum possible score, final score, and threshold used for filtering. The field is omitted unless `explain` is enabled, so existing response shapes stay unchanged.
## Filter patterns
Filters help narrow down search results. Common use cases:
+1 -1
View File
@@ -104,7 +104,7 @@ results = memory.search(
## Put it into practice
- Use the <Link href="/core-concepts/memory-operations/add">Add Memory</Link> guide to persist user preferences.
- Follow <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> to tune metadata and retrieval.
- Follow <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> to tune metadata and graph writes.
## See it live
+9 -13
View File
@@ -40,7 +40,6 @@
"icon": "rocket",
"pages": [
"platform/overview",
"platform/agent-signup",
"vibecoding",
"platform/mem0-mcp",
"platform/cli",
@@ -71,7 +70,6 @@
"pages": [
"platform/features/v2-memory-filters",
"platform/features/entity-scoped-memory",
"platform/features/graph-memory",
"platform/features/async-client",
"platform/features/multimodal-support",
"platform/features/custom-categories",
@@ -144,8 +142,7 @@
"icon": "robot",
"pages": [
"integrations/openclaw",
"integrations/hermes",
"integrations/pi-agent"
"integrations/hermes"
]
}
]
@@ -247,7 +244,6 @@
"components/vectordbs/dbs/cassandra",
"components/vectordbs/dbs/s3_vectors",
"components/vectordbs/dbs/databricks",
"components/vectordbs/dbs/neon",
"components/vectordbs/dbs/neptune_analytics",
"components/vectordbs/dbs/turbopuffer"
]
@@ -305,8 +301,7 @@
"group": "Migration",
"icon": "arrow-right",
"pages": [
"migration/oss-v2-to-v3",
"migration/server-pgvector-upgrade"
"migration/oss-v2-to-v3"
]
},
{
@@ -456,9 +451,7 @@
"pages": [
"integrations/claude-code",
"integrations/cursor",
"integrations/codex",
"integrations/opencode",
"integrations/antigravity"
"integrations/codex"
]
},
{
@@ -466,8 +459,7 @@
"icon": "robot",
"pages": [
"integrations/openclaw",
"integrations/hermes",
"integrations/pi-agent"
"integrations/hermes"
]
}
]
@@ -648,6 +640,10 @@
"source": "/open-source/features/custom-fact-extraction-prompt",
"destination": "/open-source/features/custom-instructions"
},
{
"source": "/platform/features/graph-memory",
"destination": "/migration/oss-v2-to-v3"
},
{
"source": "/cookbooks/essentials/choosing-memory-architecture-vector-vs-graph",
"destination": "/migration/oss-v2-to-v3"
@@ -1022,7 +1018,7 @@
},
{
"source": "/features/graph-memory",
"destination": "/platform/features/graph-memory"
"destination": "/migration/oss-v2-to-v3"
},
{
"source": "/features/:slug",
Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

-82
View File
@@ -1,82 +0,0 @@
---
title: Antigravity
description: "Add persistent memory to Google Antigravity with the Mem0 plugin — MCP server, lifecycle hooks, and slash commands."
---
Add persistent memory to [**Google Antigravity**](https://antigravity.google) (`agy` CLI and Desktop IDE) with the Mem0 plugin. Your agent forgets everything between sessions — Mem0 fixes that by storing decisions, preferences, and learnings so they carry over automatically.
## Prerequisites
1. A Mem0 API key (starts with `m0-`):
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-antigravity" rel="nofollow">Get your API key</a> (free sign-up at <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-antigravity" rel="nofollow">app.mem0.ai</a>)
2. Add it to your shell profile so it persists across sessions:
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc && source ~/.zshrc
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc && source ~/.bashrc
```
</CodeGroup>
## Installation
**Option A — degit** (recommended):
```bash
# Install the plugin (MCP server, hooks, scripts)
npx degit mem0ai/mem0/integrations/mem0-plugin ~/.gemini/config/plugins/mem0
```
This installs the MCP server, lifecycle hooks, and shared scripts.
## What's Included
| Component | Included |
|-----------|:--------:|
| MCP Server (9 memory tools) | Yes |
| Lifecycle Hooks | Yes |
| 16 Slash Commands | Yes |
## Available MCP Tools
| Tool | Description |
|------|-------------|
| `add_memory` | Save text or conversation history for a user/agent |
| `search_memories` | Semantic search across memories with filters |
| `get_memories` | List memories with filters and pagination |
| `get_memory` | Retrieve a specific memory by ID |
| `update_memory` | Overwrite a memory's text by ID |
| `delete_memory` | Delete a single memory by ID |
| `delete_all_memories` | Bulk delete all memories in scope |
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
## Lifecycle Hooks
The plugin uses the same shell scripts as Claude Code, Cursor, and Codex — hooks bridge environment variables using `${extensionPath}` (Antigravity's plugin-root token).
| Hook | Event | What it does |
|------|-------|-------------|
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message |
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tools |
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
## Troubleshooting
- **No tools appearing** — Restart your Antigravity session after installation
- **"Connection failed"** — Verify your key is set: `echo $MEM0_API_KEY`
- **MCP 401 Unauthorized** — If `${MEM0_API_KEY}` interpolation doesn't work in your `agy` version, replace with your literal key in `mcp_config.json`
<CardGroup cols={2}>
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
Detailed MCP configuration for all clients
</Card>
<Card title="OpenCode Integration" icon="code" href="/integrations/opencode">
Add Mem0 memory to OpenCode workflows
</Card>
</CardGroup>
+25 -43
View File
@@ -5,6 +5,13 @@ description: "Add persistent memory to Claude Code and Claude Cowork with the Me
Add persistent memory to [**Claude Code**](https://docs.anthropic.com/en/docs/claude-code) (CLI) and **Claude Cowork** (desktop app) with the Mem0 plugin. Your agent forgets everything between sessions — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
## Overview
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
2. **Lifecycle Hooks** — Automatic memory capture at session start, context compaction, task completion, and session end
3. **SDK Skill** — Teaches the agent how to integrate the Mem0 SDK into your applications
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
## Prerequisites
Before setting up Mem0 with Claude Code, ensure you have:
@@ -15,25 +22,10 @@ Before setting up Mem0 with Claude Code, ensure you have:
2. Claude Code CLI or Claude Cowork desktop app installed
3. Your API key added to your shell profile (persists across sessions):
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
source ~/.zshrc
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
source ~/.bashrc
```
</CodeGroup>
Confirm it's set:
3. Your API key exported in your shell:
```bash
echo $MEM0_API_KEY
# Should print: m0-your-api-key
export MEM0_API_KEY="m0-your-api-key"
```
## Installation
@@ -92,22 +84,6 @@ Add to your Claude Code MCP config (`.mcp.json`):
Start a new session and ask: *"List my mem0 entities"* or *"Search my memories for hello"*. If the `mem0` tools appear and respond, you're all set.
</Info>
## Post-Installation: Run `/mem0:onboard`
After installing the plugin, start a new Claude Code session and run:
```
/mem0:onboard
```
This runs the setup wizard which:
1. Verifies your API key and MCP connection
2. Detects and imports project files (`CLAUDE.md`, `AGENTS.md`, `.cursorrules`)
3. Installs coding-optimized memory categories
4. Shows your identity (user ID, project scope, branch)
The onboarding is idempotent — safe to re-run anytime. It auto-triggers on first session in a new project, but you can always invoke it manually.
## What's Included
| Component | Plugin Install | MCP Only |
@@ -136,13 +112,20 @@ Once installed, the following tools are available in every Claude Code session:
When installed via the plugin marketplace, Mem0 hooks into Claude Code's lifecycle to automatically manage memory:
| Hook | Event | What it does |
|------|-------|-------------|
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message; skips short prompts |
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
| **Pre-compact** | `PreCompact` | Stores a session summary before context compaction |
### Session Start
On every new session, the plugin prompts Claude to call `search_memories` to load relevant context from prior sessions. On resumed or post-compaction sessions, it adjusts the prompt accordingly.
### User Prompt
Before processing each user message, the plugin searches Mem0 for memories relevant to the current prompt and injects them into context. Short prompts (< 20 characters) are skipped to minimize latency.
### Pre-Compaction
Before context compaction, the plugin prompts Claude to store a comprehensive session summary — including goals, accomplishments, decisions, modified files, and current state — so nothing is lost.
### Task Completed
After each task completion, the plugin prompts Claude to extract and store key learnings: successful strategies, failed approaches, architectural decisions, and new conventions.
### Session End
When Claude finishes responding, the plugin prompts for any unstored learnings and captures transcript state via the Mem0 REST API as a background safety net.
## Example Workflow
@@ -166,10 +149,9 @@ You: Add refresh token rotation to the auth system.
## Troubleshooting
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`. If empty, add it to your shell profile (see Prerequisites)
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`
- **No tools appearing** — Restart your Claude Code session after installation
- **Memories not being captured** — Ensure you installed via the plugin marketplace (Option A) for lifecycle hooks. MCP-only installs require manual memory operations
- **"Mem0 Inactive" banner every session** — Your API key isn't persisting. Add `export MEM0_API_KEY="m0-..."` to your `~/.zshrc` (or `~/.bashrc`) and run `source ~/.zshrc`
- **Memories not being captured** — Ensure you installed via the plugin marketplace (Option A) for lifecycle hooks. MCP-only installs require manual memory operations.
<CardGroup cols={2}>
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
+124 -49
View File
@@ -1,9 +1,16 @@
---
title: Codex
description: "Add persistent memory to OpenAI Codex with the Mem0 plugin — MCP server, lifecycle hooks, and SDK skill."
description: "Add persistent memory to OpenAI Codex with the Mem0 plugin — MCP server, memory protocol skill, and plugin marketplace support."
---
Add persistent memory to [**OpenAI Codex**](https://openai.com/index/codex/) with the Mem0 plugin. Codex forgets everything between tasks — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
Add persistent memory to [**OpenAI Codex**](https://openai.com/index/codex/) with the Mem0 plugin. Codex forgets everything between tasks — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP and using a skill-based memory protocol to automatically retrieve context and store learnings.
## Overview
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
2. **Memory Protocol Skill** — Instructs the agent to retrieve memories at task start, store learnings on completion, and capture session state before context loss
3. **Plugin Marketplace** — Install via Codex's repo-level or personal plugin marketplace
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
## Prerequisites
@@ -15,41 +22,17 @@ Before setting up Mem0 with Codex, ensure you have:
2. OpenAI Codex access
3. Your API key added to your shell profile (persists across sessions):
3. Your API key exported in your shell:
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
source ~/.zshrc
```bash
export MEM0_API_KEY="m0-your-api-key"
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
source ~/.bashrc
```
</CodeGroup>
## Installation
### Option A — Plugin Marketplace (Recommended)
### Option A — Direct MCP (Recommended)
Install the full plugin including MCP server, lifecycle hooks, and SDK skill.
1. Add the Mem0 marketplace:
```bash
codex plugin marketplace add mem0ai/mem0
```
2. Restart Codex, open the Plugin Directory, browse the **Mem0 Plugins** marketplace, and install **Mem0**.
<Info>
Do not combine with Option B. The plugin manifest auto-registers the `mem0` MCP server, so adding both will create a duplicate registration.
</Info>
### Option B — Direct MCP
The fastest way to connect Codex to Mem0 — no plugin, no marketplace. Add to `~/.codex/config.toml`:
The fastest way to connect Codex to Mem0 — no downloads, no marketplace. Codex reads MCP servers from `~/.codex/config.toml` as TOML. Add:
```toml
[mcp_servers.mem0]
@@ -63,16 +46,71 @@ Make sure `MEM0_API_KEY` is exported in the shell you launch Codex from, then re
Codex's `codex mcp add` CLI only supports stdio MCP servers. Because Mem0's MCP is HTTP/streamable, you configure it by editing `config.toml` directly (or via the **Plugins → Connect to a custom MCP → Streamable HTTP** UI in the Codex app).
</Info>
This gives you the MCP tools but not the lifecycle hooks or SDK skill.
### Option B — Sideload the Plugin (Advanced)
For the full plugin experience — MCP server **plus** the Mem0 SDK skill, memory protocol skill, and opt-in lifecycle hooks — sideload the plugin from a local clone. The Mem0 repo already ships a marketplace manifest at [`.agents/plugins/marketplace.json`](https://github.com/mem0ai/mem0/blob/main/.agents/plugins/marketplace.json), so there's no JSON to author by hand. This follows the Codex [build-plugins](https://developers.openai.com/codex/plugins/build) local-testing workflow.
<Info>
Don't combine Option B with Option A. The plugin manifest declares its MCP server via [`.codex-mcp.json`](https://github.com/mem0ai/mem0/blob/main/mem0-plugin/.codex-mcp.json), so Codex auto-registers the `mem0` MCP server when the plugin loads. Adding the same `[mcp_servers.mem0]` block to `~/.codex/config.toml` will create a duplicate registration.
</Info>
**Step 1.** Clone the Mem0 repository anywhere on disk:
```bash
git clone https://github.com/mem0ai/mem0.git ~/codex-plugins/mem0-source
```
**Step 2.** Register the bundled marketplace with Codex's CLI:
```bash
codex plugin marketplace add ~/codex-plugins/mem0-source
```
This points Codex at the repo's `.agents/plugins/marketplace.json`. The bundled file uses `path: "./mem0-plugin"`, which Codex resolves relative to the clone root.
<Info>
**Why we recommend this over hand-authoring `~/.agents/plugins/marketplace.json`:** Codex requires `source.path` in any marketplace manifest to be **relative** (starting with `./`) and **inside the marketplace root**. The repo's bundled manifest already satisfies this — the marketplace root is the clone directory, and `mem0-plugin/` lives inside it. With a personal `~/.agents/plugins/marketplace.json`, the root is `~/` and the clone has to live under `~/` too. The CLI form sidesteps that constraint.
</Info>
**Step 3.** Restart Codex, run `/plugins`, browse the `Mem0 Plugins` marketplace, and install **Mem0**.
**Step 4 (optional) — enable lifecycle hooks.** Codex doesn't auto-wire hooks from plugin manifests; it only reads them from `~/.codex/hooks.json` (or `<repo>/.codex/hooks.json`). Run the bundled installer once to merge the Mem0 entries into your global hooks file:
```bash
python3 ~/codex-plugins/mem0-source/mem0-plugin/scripts/install_codex_hooks.py
```
Then enable the hooks feature flag in `~/.codex/config.toml`:
```toml
[features]
codex_hooks = true
```
Restart Codex. The installer registers three hooks pointing at scripts inside your clone:
| Event | Behavior |
|-------|----------|
| `SessionStart` | Loads prior memories as bootstrap context |
| `UserPromptSubmit` | Injects relevant memories before each prompt |
| `Stop` | Reminds the agent to persist learnings at turn end |
Re-running the installer is idempotent. To remove the hooks: `python3 ~/codex-plugins/mem0-source/mem0-plugin/scripts/install_codex_hooks.py --uninstall`.
<Warning>
The hooks file stores absolute paths into your clone (e.g. `~/codex-plugins/mem0-source/mem0-plugin/scripts/...`). If you move or delete the clone, the hooks will break silently — re-run the installer from the new location, or run `--uninstall` first.
</Warning>
### Managing the Plugin
Codex provides CLI commands for managing marketplaces after install:
```bash
codex plugin marketplace upgrade # pull latest plugin versions
codex plugin marketplace remove mem0-plugins # unregister the marketplace
```
To update, run `codex plugin marketplace upgrade` to pull the latest from the Mem0 repo.
To pull updates to the plugin source itself, `git pull` inside your clone (`~/codex-plugins/mem0-source`) and then run `codex plugin marketplace upgrade` to refresh Codex's plugin cache. Plugins are cached at `~/.codex/plugins/cache/<marketplace>/<plugin>/<version>/`.
<Info icon="check">
After either option, start a new Codex task and ask: *"List my mem0 entities"* or *"Search my memories for hello"*. If the `mem0` tools appear and respond, you're all set.
@@ -80,11 +118,12 @@ To update, run `codex plugin marketplace upgrade` to pull the latest from the Me
## What's Included
| Component | Plugin Install | MCP Only |
|-----------|:--------------:|:--------:|
| Component | Sideloaded Plugin | Direct MCP |
|-----------|:-----------------:|:----------:|
| MCP Server (9 memory tools) | Yes | Yes |
| Lifecycle Hooks | Yes | No |
| Memory Protocol Skill | Yes | No |
| Mem0 SDK Skill | Yes | No |
| Lifecycle Hooks (opt-in) | Yes | No |
## Available MCP Tools
@@ -102,17 +141,49 @@ Once installed, the following tools are available in every Codex session:
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
## Lifecycle Hooks
## Memory Protocol Skill
When installed via the plugin marketplace, Mem0 hooks into Codex's lifecycle to automatically manage memory:
When the plugin is sideloaded, the memory protocol skill instructs the agent to:
| Hook | Event | What it does |
|------|-------|-------------|
| **Session start** | `SessionStart` | Loads prior memories and displays status banner |
| **User prompt** | `UserPromptSubmit` | Searches relevant memories before each message |
| **Pre-tool** | `PreToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
| **Post-tool** | `PostToolUse` | Tracks stats, scans bash errors for related memories |
| **Pre-compact** | `PreCompact` | Stores a session summary before context compaction |
### On Every New Task
1. Call `search_memories` with a query related to the current task to load relevant context
2. Review returned memories to understand what was learned in prior sessions
3. Optionally call `get_memories` to browse all stored memories
### After Completing Significant Work
Store key learnings using `add_memory` with structured metadata:
| What to store | Metadata type |
|--------------|---------------|
| Architectural decisions | `{"type": "decision"}` |
| Strategies that worked | `{"type": "task_learning"}` |
| Failed approaches | `{"type": "anti_pattern"}` |
| User preferences observed | `{"type": "user_preference"}` |
| Environment discoveries | `{"type": "environmental"}` |
| Conventions established | `{"type": "convention"}` |
### Before Losing Context
Store a comprehensive session summary including goals, accomplishments, decisions, files modified, and current state with metadata `{"type": "session_state"}`.
## Plugin Manifest
The Codex plugin manifest (`.codex-plugin/plugin.json`) follows the Codex plugin specification:
```json
{
"name": "mem0",
"version": "0.1.0",
"description": "Mem0 memory layer for AI applications.",
"skills": "./skills/",
"mcpServers": "./.codex-mcp.json",
"interface": {
"displayName": "Mem0",
"shortDescription": "Persistent memory layer for AI coding workflows",
"category": "Productivity",
"capabilities": ["Read", "Write"]
}
}
```
## Example Workflow
@@ -135,10 +206,14 @@ You: Add WebSocket support for real-time notification delivery.
## Troubleshooting
- **"Connection failed"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`
- **No tools appearing** — Restart your Codex session after installation
- **Duplicate `mem0` MCP / "tool collision" errors** — You combined Option A with Option B. Remove the `[mcp_servers.mem0]` block from `~/.codex/config.toml`; the plugin registers it automatically
- **Hooks not firing** — Ensure the plugin is installed via the marketplace (Option A). MCP-only installs do not include hooks
- **"Connection failed"** — Verify `MEM0_API_KEY` is set in your shell: `echo $MEM0_API_KEY`
- **No tools appearing** — Restart your Codex session after plugin installation
- **Duplicate `mem0` MCP server / "tool collision" errors** — You combined Option A (Direct MCP) with Option B (sideload). The sideloaded plugin auto-registers `mem0` from `.codex-mcp.json`, so remove the `[mcp_servers.mem0]` block from `~/.codex/config.toml`.
- **`plugin/read failed in TUI`** — Codex can't find the plugin directory the marketplace points at. If you used `codex plugin marketplace add <path>`, confirm the path is your clone root and that `<clone>/.agents/plugins/marketplace.json` exists. If you hand-authored `~/.agents/plugins/marketplace.json`, `source.path` must be relative (start with `./`), inside the marketplace root (`~/` for personal installs), and end in `mem0-plugin` — e.g. `"./codex-plugins/mem0-source/mem0-plugin"`.
- **Plugin not found in `/plugins`** — Run `codex plugin marketplace add ~/path/to/clone` again, or confirm the marketplace was registered with `codex plugin marketplace remove mem0-plugins` then re-add.
- **Skills not loading** — Verify the `skills` field in `plugin.json` points to a valid directory containing `SKILL.md` files.
- **Hooks not firing** — Confirm `codex_hooks = true` is in `~/.codex/config.toml` under `[features]`, and that `~/.codex/hooks.json` contains the Mem0 entries (re-run the installer if not). Restart Codex after enabling the flag.
- **Hooks broke after moving the clone** — The installer bakes absolute paths into `~/.codex/hooks.json` pointing at scripts inside your clone. If you moved or renamed the clone directory, run `python3 <new-clone>/mem0-plugin/scripts/install_codex_hooks.py` from the new location — the installer is idempotent and replaces the old entries.
<CardGroup cols={2}>
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
+18 -18
View File
@@ -5,6 +5,13 @@ description: "Add persistent memory to Cursor with the Mem0 plugin — MCP serve
Add persistent memory to [**Cursor**](https://cursor.com) with the Mem0 plugin. Your AI assistant forgets everything between sessions — this plugin fixes that by connecting to Mem0's cloud memory layer via MCP, automatically capturing learnings at key lifecycle points, and retrieving relevant context before every response.
## Overview
1. **MCP Server** — Connect to Mem0's remote MCP server for memory tools (add, search, update, delete)
2. **Lifecycle Hooks** — Automatic memory capture at session start, compaction, and user prompts (Marketplace install)
3. **SDK Skill** — Teaches the agent how to integrate the Mem0 SDK into your applications
4. **Zero local dependencies** — Cloud-hosted MCP server, no local setup required
## Prerequisites
Before setting up Mem0 with Cursor, ensure you have:
@@ -15,20 +22,12 @@ Before setting up Mem0 with Cursor, ensure you have:
2. Cursor installed ([cursor.com](https://cursor.com))
3. Your API key added to your shell profile (persists across sessions):
3. Your API key exported in your shell:
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
source ~/.zshrc
```bash
export MEM0_API_KEY="m0-your-api-key"
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
source ~/.bashrc
```
</CodeGroup>
<Warning>
Already have `mem0` configured as an MCP server in Cursor? Remove the existing entry from your Cursor MCP settings before installing to avoid duplicate tools.
</Warning>
@@ -104,13 +103,14 @@ Once installed, the following tools are available in every Cursor session:
When installed via the Cursor Marketplace, Mem0 hooks into Cursor's lifecycle:
| Hook | Event | What it does |
|------|-------|-------------|
| **Session start** | `sessionStart` | Loads prior memories and displays status banner |
| **User prompt** | `beforeSubmitPrompt` | Searches relevant memories before each message; skips short prompts |
| **Pre-tool (2 handlers)** | `preToolUse` | Blocks MEMORY.md writes, enforces `user_id`/`app_id` on mem0 tool calls |
| **Post-tool (2 handlers)** | `postToolUse` | Tracks stats, scans bash errors for related memories |
| **Pre-compact** | `preCompact` | Stores a session summary before context compaction |
### Session Start
On every new session, the plugin prompts the agent to call `search_memories` to load relevant context from prior sessions.
### User Prompt
Before processing each user message, the plugin searches Mem0 for relevant memories and injects them into context. Short prompts are skipped to minimize latency.
### Pre-Compaction
Before context compaction, the plugin captures a comprehensive session summary so nothing is lost when the context window resets.
## Example Workflow
+191 -243
View File
@@ -7,338 +7,285 @@ Integrate [**Mem0**](https://github.com/mem0ai/mem0) with [Google ADK (Agent Dev
## Overview
In this guide, we'll create a Google ADK agent that:
1. Uses ADK's native `MemoryService` interface to connect Mem0
2. Automatically injects relevant memories using ADK's built-in `load_memory` tool
3. Persists session history to Mem0 after each turn via an after-agent callback
4. Shares memory seamlessly across multi-agent hierarchies
1. Store and retrieve memories from Mem0 within Google ADK agents
2. Multi-agent workflows with shared memory across hierarchies
3. Retrieve relevant memories from past conversations
4. Personalized responses based on user history
## Setup and Configuration
## Prerequisites
Install the necessary libraries:
Before setting up Mem0 with Google ADK, ensure you have:
1. Installed the required packages:
```bash
pip install google-adk mem0ai python-dotenv
```
Set up your API keys:
2. Valid API keys:
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-google-ai-adk" rel="nofollow">Mem0 API Key</a>
- Google AI Studio API Key
<Note>Remember to get your API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a> and set up a [Google AI Studio API Key](https://aistudio.google.com/apikey).</Note>
## Basic Integration Example
The following example demonstrates how to create a Google ADK agent with Mem0 memory integration:
```python
import os
import asyncio
from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
from mem0 import MemoryClient
from dotenv import load_dotenv
load_dotenv()
# Set up environment variables
# os.environ["GOOGLE_API_KEY"] = "your-google-api-key"
# os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
```
## Implement Mem0MemoryService
# Initialize Mem0 client
mem0 = MemoryClient()
Create a custom `MemoryService` by implementing ADK's `BaseMemoryService`. Save the following as **`mem0_memory_service.py`**:
# Define memory function tools
def search_memory(query: str, user_id: str) -> dict:
"""Search through past conversations and memories"""
# For Platform API, user_id goes in filters
filters = {"user_id": user_id}
memories = mem0.search(query, filters=filters)
if memories.get('results', []):
memory_list = memories['results']
memory_context = "\n".join([f"- {mem['memory']}" for mem in memory_list])
return {"status": "success", "memories": memory_context}
return {"status": "no_memories", "message": "No relevant memories found"}
```python
import asyncio
import os
from typing import Optional
from typing_extensions import override
from google.adk.memory.base_memory_service import BaseMemoryService, SearchMemoryResponse
from google.adk.memory.memory_entry import MemoryEntry
from google.adk.sessions import Session
from google.genai.types import Content, Part
from mem0 import MemoryClient
class Mem0MemoryService(BaseMemoryService):
"""MemoryService implementation backed by the Mem0 Platform."""
def __init__(self, api_key: Optional[str] = None):
super().__init__()
api_key = api_key or os.environ.get("MEM0_API_KEY")
self._client: Optional[MemoryClient] = MemoryClient(api_key=api_key) if api_key else None
@override
async def search_memory(
self, *, app_name: str, user_id: str, query: str
) -> SearchMemoryResponse:
"""Search for memories relevant to the current user and query."""
if not self._client:
return SearchMemoryResponse(memories=[])
try:
results = await asyncio.to_thread(
self._client.search,
query,
filters={"AND": [{"user_id": user_id}, {"app_id": app_name}]},
top_k=5,
)
entries = []
for mem in results.get("results", []):
text = mem.get("memory", "")
if not text:
continue
raw_ts = mem.get("created_at") or mem.get("updated_at")
entries.append(
MemoryEntry(
content=Content(parts=[Part(text=text)]),
author=mem.get("metadata", {}).get("author", "user"),
timestamp=str(raw_ts) if raw_ts else None,
)
)
return SearchMemoryResponse(memories=entries)
except Exception as e:
print(f"[Mem0MemoryService] search_memory error: {e}")
return SearchMemoryResponse(memories=[])
@override
async def add_session_to_memory(self, session: Session) -> None:
"""Persist a completed ADK session into Mem0."""
if not self._client:
return
user_id = session.user_id
if not user_id:
return
app_name = getattr(session, "app_name", None)
try:
messages = []
for event in session.events:
if not (event.content and event.content.parts):
continue
role = getattr(event.content, "role", None) or "user"
if role == "model":
role = "assistant"
elif role not in ("user", "assistant"):
continue
text_parts = [
p.text for p in event.content.parts if hasattr(p, "text") and p.text
]
if text_parts:
messages.append({"role": role, "content": " ".join(text_parts)})
if messages:
metadata = {"app_id": app_name} if app_name else {}
await asyncio.to_thread(
self._client.add, messages, user_id=user_id, metadata=metadata
)
except Exception as e:
print(f"[Mem0MemoryService] add_session_to_memory error: {e}")
```
## Add Auto-Save Callback
This after-agent callback fires at the end of every turn and saves the session to Mem0. Save as **`memory_callbacks.py`**:
```python
async def save_session_to_memory(callback_context) -> None:
"""Persist the completed session to Mem0 after each agent turn."""
def save_memory(content: str, user_id: str) -> dict:
"""Save important information to memory"""
try:
await callback_context.add_session_to_memory()
except ValueError:
pass
result = mem0.add([{"role": "user", "content": content}], user_id=user_id)
return {"status": "success", "message": "Information saved to memory", "result": result}
except Exception as e:
print(f"[save_session_to_memory] error: {e}")
```
return {"status": "error", "message": f"Failed to save memory: {str(e)}"}
## Basic Integration Example
The following example demonstrates creating an ADK agent with automatic Mem0 memory:
```python
import asyncio
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.tools import load_memory
from google.genai.types import Content, Part
from mem0_memory_service import Mem0MemoryService
from memory_callbacks import save_session_to_memory
memory_service = Mem0MemoryService()
session_service = InMemorySessionService()
agent = LlmAgent(
# Create agent with memory capabilities
personal_assistant = Agent(
name="personal_assistant",
model="gemini-2.0-flash",
instruction="""You are a helpful personal assistant.
Relevant memories from past conversations are provided to you automatically.
Use them to personalize your responses.""",
instruction="""You are a helpful personal assistant with memory capabilities.
Use the search_memory function to recall past conversations and user preferences.
Use the save_memory function to store important information about the user.
Always personalize your responses based on available memory.""",
description="A personal assistant that remembers user preferences and past interactions",
tools=[load_memory],
after_agent_callback=save_session_to_memory,
tools=[search_memory, save_memory]
)
runner = Runner(
agent=agent,
session_service=session_service,
memory_service=memory_service,
app_name="memory_assistant",
)
async def chat_with_agent(user_input: str, user_id: str) -> str:
"""
Handle user input with automatic memory integration.
Args:
user_input: The user's message
user_id: Unique identifier for the user
async def chat(user_input: str, user_id: str) -> str:
Returns:
The agent's response
"""
# Set up session and runner
session_service = InMemorySessionService()
session = await session_service.create_session(
app_name="memory_assistant",
user_id=user_id,
session_id=f"session_{user_id}"
)
content = Content(role="user", parts=[Part(text=user_input)])
async for event in runner.run_async(user_id=user_id, session_id=session.id, new_message=content):
if event.is_final_response() and event.content and event.content.parts:
return event.content.parts[0].text
runner = Runner(agent=personal_assistant, app_name="memory_assistant", session_service=session_service)
# Create content and run agent
content = types.Content(role='user', parts=[types.Part(text=user_input)])
events = runner.run(user_id=user_id, session_id=session.id, new_message=content)
# Extract final response
for event in events:
if event.is_final_response():
response = event.content.parts[0].text
return response
return "No response generated"
# Example usage
if __name__ == "__main__":
print(asyncio.run(chat(
response = asyncio.run(chat_with_agent(
"I love Italian food and I'm planning a trip to Rome next month",
user_id="alice",
)))
print(asyncio.run(chat(
"Any food recommendations for my trip?",
user_id="alice",
)))
user_id="alice"
))
print(response)
```
## Multi-Agent Hierarchy with Shared Memory
Because `memory_service` is passed to the `Runner`, every agent in the hierarchy shares the same memory automatically. Only the root coordinator needs the auto-save callback — ADK fires it once when the full turn completes:
Create specialized agents in a hierarchy that share memory:
```python
import asyncio
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.tools.agent_tool import AgentTool
from google.adk.tools import load_memory
from google.genai.types import Content, Part
from mem0_memory_service import Mem0MemoryService
from memory_callbacks import save_session_to_memory
memory_service = Mem0MemoryService()
session_service = InMemorySessionService()
travel_agent = LlmAgent(
# Travel specialist agent
travel_agent = Agent(
name="travel_specialist",
model="gemini-2.0-flash",
instruction="""You are a travel planning specialist.
Relevant memories about the user's travel preferences are provided automatically.
Use them to make personalized recommendations.""",
instruction="""You are a travel planning specialist. Use search_memory to
understand the user's travel preferences and history before making recommendations.
After providing advice, use save_memory to save travel-related information.""",
description="Specialist in travel planning and recommendations",
tools=[load_memory],
tools=[search_memory, save_memory]
)
health_agent = LlmAgent(
# Health advisor agent
health_agent = Agent(
name="health_advisor",
model="gemini-2.0-flash",
instruction="""You are a health and wellness advisor.
Relevant memories about the user's health goals are provided automatically.
Use them to give personalized advice.""",
instruction="""You are a health and wellness advisor. Use search_memory to
understand the user's health goals and dietary preferences.
After providing advice, use save_memory to save health-related information.""",
description="Specialist in health and wellness advice",
tools=[load_memory],
tools=[search_memory, save_memory]
)
coordinator = LlmAgent(
# Coordinator agent that delegates to specialists
coordinator_agent = Agent(
name="coordinator",
model="gemini-2.0-flash",
instruction="""You are a coordinator that delegates requests to specialist agents.
For travel-related questions, delegate to the travel specialist.
For health-related questions, delegate to the health advisor.
Relevant memories about the user are provided automatically.""",
For travel-related questions (trips, hotels, flights, destinations), delegate to the travel specialist.
For health-related questions (fitness, diet, wellness, exercise), delegate to the health advisor.
Use search_memory to understand the user before delegation.""",
description="Coordinates requests between specialist agents",
tools=[
load_memory,
AgentTool(agent=travel_agent, skip_summarization=False),
AgentTool(agent=health_agent, skip_summarization=False),
],
after_agent_callback=save_session_to_memory,
AgentTool(agent=health_agent, skip_summarization=False)
]
)
runner = Runner(
agent=coordinator,
session_service=session_service,
memory_service=memory_service,
app_name="specialist_system",
)
def chat_with_specialists(user_input: str, user_id: str) -> str:
"""
Handle user input with specialist agent delegation and memory.
Args:
user_input: The user's message
user_id: Unique identifier for the user
async def chat_with_specialists(user_input: str, user_id: str) -> str:
session = await session_service.create_session(
Returns:
The specialist agent's response
"""
session_service = InMemorySessionService()
session = session_service.create_session(
app_name="specialist_system",
user_id=user_id,
session_id=f"session_{user_id}"
)
content = Content(role="user", parts=[Part(text=user_input)])
async for event in runner.run_async(user_id=user_id, session_id=session.id, new_message=content):
if event.is_final_response() and event.content and event.content.parts:
return event.content.parts[0].text
runner = Runner(agent=coordinator_agent, app_name="specialist_system", session_service=session_service)
content = types.Content(role='user', parts=[types.Part(text=user_input)])
events = runner.run(user_id=user_id, session_id=session.id, new_message=content)
for event in events:
if event.is_final_response():
response = event.content.parts[0].text
# Store the conversation in shared memory
conversation = [
{"role": "user", "content": user_input},
{"role": "assistant", "content": response}
]
mem0.add(conversation, user_id=user_id)
return response
return "No response generated"
# Example usage
response = chat_with_specialists("Plan a healthy meal for my Italy trip", user_id="alice")
print(response)
```
## Quick Start Chat Interface
Simple interactive chat with memory and Google ADK:
```python
def interactive_chat():
"""Interactive chat interface with memory and ADK"""
user_id = input("Enter your user ID: ") or "demo_user"
print(f"Chat started for user: {user_id}")
print("Type 'quit' to exit")
print("=" * 50)
while True:
user_input = input("\nYou: ")
if user_input.lower() == 'quit':
print("Goodbye! Your conversation has been saved to memory.")
break
else:
response = chat_with_specialists(user_input, user_id)
print(f"Assistant: {response}")
if __name__ == "__main__":
response = asyncio.run(chat_with_specialists("Plan a healthy meal for my Italy trip", user_id="alice"))
print(response)
interactive_chat()
```
## Key Features
1. **Automatic Memory Injection**: ADK's built-in `load_memory` tool searches Mem0 at the start of each turn and injects relevant memories directly into the agent context — no prompt instructions needed.
2. **Automatic Session Saving**: The `save_session_to_memory` callback persists every completed turn to Mem0 without any manual calls.
3. **Native ADK Integration**: `Mem0MemoryService` implements ADK's `BaseMemoryService` and integrates via the `Runner` — works natively across the entire agent hierarchy.
4. **User Scoping**: `user_id` is passed automatically from the ADK session context, ensuring memories are always scoped to the correct user.
5. **Multi-Agent Support**: A single `Mem0MemoryService` instance shared through the `Runner` gives all agents — coordinators and specialists — access to the same user memory.
### 1. Memory-Enhanced Function Tools
- **Function Tools**: Standard Python functions that can search and save memories
- **Tool Context**: Access to session state and memory through function parameters
- **Structured Returns**: Dictionary-based returns with status indicators for better LLM understanding
### 2. Multi-Agent Memory Sharing
- **Agent-as-a-Tool**: Specialists can be called as tools while maintaining shared memory
- **Hierarchical Delegation**: Coordinator agents route to specialists based on context
- **Memory Categories**: Store interactions with metadata for better organization
### 3. Flexible Memory Operations
- **Search Capabilities**: Retrieve relevant memories through conversation history
- **User Segmentation**: Organize memories by user ID
- **Memory Management**: Built-in tools for saving and retrieving information
## Configuration Options
### Using Vertex AI
To use Google Cloud Vertex AI instead of AI Studio, set the following environment variables before creating agents:
Customize memory behavior and agent setup:
```python
import os
# Configure memory search with filters
# For Platform API, all filters including user_id go in filters object
memories = mem0.search(
query="travel preferences",
filters={
"AND": [
{"user_id": "alice"},
{"categories": {"contains": "travel"}}
]
},
top_k=5
)
# Configure agent with custom model settings
agent = Agent(
name="custom_agent",
model="gemini-2.0-flash", # or use LiteLLM for other models
instruction="Custom agent behavior",
tools=[memory_tools],
# Additional ADK configurations
)
# Use Google Cloud Vertex AI instead of AI Studio
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
os.environ["GOOGLE_CLOUD_PROJECT"] = "your-project-id"
os.environ["GOOGLE_CLOUD_LOCATION"] = "us-central1"
```
### Advanced Memory Filtering
You can customize how memories are searched by modifying `Mem0MemoryService.search_memory`. For example, to filter by category:
```python
results = await asyncio.to_thread(
self._client.search,
query,
filters={
"AND": [
{"user_id": user_id},
{"app_id": app_name},
{"categories": {"contains": "travel"}}
]
},
top_k=10,
)
```
<Note>`InMemorySessionService` stores sessions in memory and is intended for prototyping. For production, use a persistent session service and clean up sessions when they are no longer needed.</Note>
## Conclusion
By implementing `Mem0MemoryService` as an ADK `BaseMemoryService`, you get persistent, user-scoped memory across single agents and complex multi-agent hierarchies with minimal code. Memory injection and session saving happen automatically, keeping your agent prompts clean and your token usage efficient.
<CardGroup cols={2}>
<Card title="Healthcare Agent Cookbook" icon="heart-pulse" href="/cookbooks/integrations/healthcare-google-adk">
Build HIPAA-compliant healthcare agents with Google ADK
@@ -347,3 +294,4 @@ By implementing `Mem0MemoryService` as an ADK `BaseMemoryService`, you get persi
Compare with OpenAI's agent framework
</Card>
</CardGroup>
-154
View File
@@ -1,154 +0,0 @@
---
title: OpenCode
description: "Add persistent memory to OpenCode with the Mem0 plugin — native SDK-backed memory tools, lifecycle hooks, and skills."
---
Add persistent memory to [**OpenCode**](https://opencode.ai) with the Mem0 plugin. Your agent forgets everything between sessions — Mem0 fixes that by storing decisions, preferences, and learnings so they carry over automatically.
## Prerequisites
1. A Mem0 API key (starts with `m0-`):
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-opencode" rel="nofollow">Get your API key</a> (free sign-up at <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-opencode" rel="nofollow">app.mem0.ai</a>)
2. Add it to your shell profile so it persists across sessions:
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc && source ~/.zshrc
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc && source ~/.bashrc
```
</CodeGroup>
## Installation
### Option A — Plugin Install (Recommended)
```bash
opencode plugin @mem0/opencode-plugin
```
**Or let your agent do it** — paste this into OpenCode:
```
Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/integrations/mem0-plugin/.opencode-plugin/README.md
```
This adds the plugin to your `~/.config/opencode/opencode.json`. Restart OpenCode — you get the native memory tools, lifecycle hooks, and all `/mem0-*` slash commands. The memory tools are registered by the plugin itself via the `mem0ai` SDK — no MCP server to configure.
### Option B — Standalone MCP Server
If you only need the memory tools without the plugin's hooks or skills, point OpenCode at Mem0's hosted MCP server directly. Add this to your `opencode.json` (project-level or global at `~/.config/opencode/opencode.json`):
```json
{
"mcp": {
"mem0": {
"type": "remote",
"url": "https://mcp.mem0.ai/mcp/",
"headers": {
"Authorization": "Token {env:MEM0_API_KEY}"
},
"oauth": false
}
}
}
```
## What's Included
| Component | Plugin (A) | Standalone MCP (B) |
|-----------|:----------:|:------------------:|
| 9 memory tools | Native (SDK) | Remote MCP server |
| Lifecycle Hooks | Yes | No |
| 9 Skills | Yes | No |
## Available Memory Tools
| Tool | Description |
|------|-------------|
| `add_memory` | Save text or conversation history for a user/agent |
| `search_memories` | Semantic search across memories with filters |
| `get_memories` | List memories with filters and pagination |
| `get_memory` | Retrieve a specific memory by ID |
| `update_memory` | Overwrite a memory's text by ID |
| `delete_memory` | Delete a single memory by ID |
| `delete_all_memories` | Bulk delete all memories in scope |
| `delete_entities` | Delete a user/agent/app/run entity and its memories |
| `list_entities` | List users/agents/apps/runs stored in Mem0 |
## Memory scope
`search_memories`, `get_memories`, `add_memory`, and `delete_all_memories` accept an optional **`scope`** that controls how widely they read or write:
| Scope | Reads | Writes |
|-------|-------|--------|
| `project` *(default)* | this repo (`user_id` + `app_id`) | this repo |
| `session` | this run only (`+ run_id`) | this run |
| `global` | **all your projects in the workspace** (`app_id: "*"`) | user-wide |
Just ask naturally — e.g. *"search my memories across all my projects"* — and the agent passes `scope: "global"`. For normal questions it stays scoped to the current project automatically.
To change the **default** scope (used when no scope is passed), run the `/mem0-scope` skill:
```
/mem0-scope # show the current default scope + identity
/mem0-scope global # save & search across all your projects by default
/mem0-scope project # back to repo-only (the default)
```
The default persists in `~/.mem0/settings.json` (`default_scope`) and is read fresh on each memory operation, so a change applies immediately — no restart. `delete_all_memories` always requires an explicit `scope: "global"` to delete user-wide, so changing the default can't trigger a cross-project wipe.
The project id (`app_id`) is derived from your git remote (`owner-repo`), falling back to the git repo's root directory name, then the current directory. Launch OpenCode from inside your repo so memories scope to the project rather than your home directory.
## Lifecycle Hooks
The plugin uses the [mem0ai](https://www.npmjs.com/package/mem0ai) TypeScript SDK directly — pure TypeScript, no Python, no shell scripts.
| OpenCode Event | Hook | What happens |
|----------------|------|-------------|
| `config` | **Config** | Registers the `/mem0-*` slash commands (`config.command`) and adds the plugin's own `opencode-skills/` dir to OpenCode's `skills.paths` for in-place skill discovery (no copying) |
| `chat.message` | **Chat message** | Searches prior memories on session start, searches relevant memories before each prompt, auto-captures learnings periodically |
| `tool.execute.before` | **Pre-tool** | Blocks MEMORY.md writes, steering them to the `add_memory` tool |
| `tool.execute.after` | **Post-tool** | Scans Bash errors and pre-fetches related error memories |
| `experimental.chat.messages.transform` | **Messages transform** | Injects memory context (session memories, search results, error lookups) into the prompt |
| `experimental.session.compacting` | **Compaction** | Stores session state memory, then injects prior memories into compaction context so nothing is lost |
| `shell.env` | **Shell env** | Exports `MEM0_USER_ID`, `MEM0_APP_ID`, `MEM0_SESSION_ID`, and `MEM0_BRANCH` to all shell executions |
## Auto-dream (memory consolidation)
The plugin can automatically consolidate stored memories — merging duplicates, dropping stale/sensitive entries, and rewriting vague ones — so your memory set stays clean over time. It runs at most once per session, and only when **all** gates pass:
- **Time** — at least `minHours` (default 24) since the last consolidation
- **Sessions** — at least `minSessions` (default 5) sessions since then
- **Memories** — at least `minMemories` (default 20) stored for the project
A filesystem lock (`~/.mem0/mem0-dream.lock`) keeps two sessions from consolidating at once. Tune the thresholds with a `dream` block in `~/.mem0/settings.json`, or disable entirely with `MEM0_DREAM=false`:
```json
{
"dream": { "enabled": true, "auto": true, "minHours": 24, "minSessions": 5, "minMemories": 20 }
}
```
If auto-dream hasn't run yet, it's almost always because a gate hasn't been met (most often too few memories). Run `/mem0-status` to see the exact gate progress (e.g. `sessions 2/5, memories 3/20`), `/mem0-dream` to consolidate **now** regardless of the gates, or lower the thresholds above.
## Troubleshooting
- **No tools appearing** — Restart OpenCode after installing
- **"Connection failed"** — Verify your key is set: `echo $MEM0_API_KEY`
- **Plugin not loading** — Run `opencode plugin @mem0/opencode-plugin` again, then restart
- **Hooks not firing** — Hooks require the plugin install (Option A). MCP-only installs don't include hooks.
- **Auto-dream never runs** — It's gated (time + sessions + memories). Run `/mem0-status` to see which gate is blocking, or `/mem0-dream` to consolidate now.
- **Wrong project name / memories not found** — The project id comes from your git remote; launch OpenCode from inside the repo (not your home directory). Check the resolved id with `/mem0-status`.
<CardGroup cols={2}>
<Card title="Mem0 MCP Setup" icon="puzzle-piece" href="/platform/mem0-mcp">
Detailed MCP configuration for all clients
</Card>
<Card title="Antigravity Integration" icon="google" href="/integrations/antigravity">
Add Mem0 memory to Google Antigravity
</Card>
</CardGroup>
-184
View File
@@ -1,184 +0,0 @@
---
title: Pi Agent
description: "Add persistent memory to Pi Agent with the Mem0 plugin semantic search, auto-capture, and dream consolidation."
---
Add persistent memory to [**Pi Agent**](https://pi.dev) with `@mem0/pi-agent-plugin`. Your agent forgets everything between sessions — this plugin fixes that by automatically capturing knowledge from conversations, storing it in Mem0's cloud memory layer, and retrieving relevant context before every response.
## Overview
The plugin provides:
1. **Auto-capture** — Extracts durable facts from both user and assistant messages automatically
2. **Semantic recall** — Retrieves relevant memories via the `mem0_memory` tool before each response
3. **Dream consolidation** — Periodic maintenance: merges duplicates, resolves contradictions, prunes stale entries
4. **Monorepo-aware scoping** — Uses git root for project detection, consistent across subdirectories
5. **Confirmation dialogs** — Destructive commands ask before acting via Pi's built-in UI
6. **8 skills + 8 commands** — Essential memory management from slash commands and agent-guided workflows
## Prerequisites
1. A Mem0 Platform account and API key:
- <a href="https://app.mem0.ai?utm_source=oss&utm_medium=integration-pi-agent" rel="nofollow">Sign up at app.mem0.ai</a>
- <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=integration-pi-agent" rel="nofollow">Get your API key</a> (starts with `m0-`)
2. Pi Agent installed ([pi.dev](https://pi.dev))
3. Your API key added to your shell profile:
<CodeGroup>
```bash zsh
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc
source ~/.zshrc
```
```bash bash
echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc
source ~/.bashrc
```
</CodeGroup>
## Installation
```bash
pi install npm:@mem0/pi-agent-plugin
```
That's it. The extension loads automatically on every Pi session. No config files needed — `MEM0_API_KEY` from your environment is picked up automatically.
<Info>
Start a new Pi session and run `/mem0-status` to verify the connection. You should see your user ID, detected project, and memory count.
</Info>
### Optional Configuration
For advanced settings, create `~/.pi/agent/mem0-config.json`:
```json
{
"apiKey": "m0-your-key-here",
"userId": "your-username",
"autoCapture": true,
"defaultScope": "project",
"searchThreshold": 0.3,
"dream": {
"enabled": true,
"auto": true,
"minHours": 24,
"minSessions": 5,
"minMemories": 20
}
}
```
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `apiKey` | `string` | `$MEM0_API_KEY` | Mem0 API key. Environment variable takes precedence. |
| `userId` | `string` | `$MEM0_USER_ID` or `"default"` | User identity for memory scoping |
| `autoCapture` | `boolean` | `true` | Store facts from conversations automatically |
| `defaultScope` | `string` | `"project"` | Default memory scope: `project`, `session`, or `global` |
| `searchThreshold` | `number` | `0.3` | Minimum similarity score (0–1) a memory must reach to count as a match for `/mem0-search`, `/mem0-forget`, and `/mem0-pin`, enforced on each result's relevance score. Raise it to be stricter; lower it if relevant results are missed. |
| `dream.enabled` | `boolean` | `true` | Enable dream consolidation |
| `dream.auto` | `boolean` | `true` | Auto-trigger dreams when thresholds are met |
| `dream.minHours` | `number` | `24` | Minimum hours between auto-dreams |
| `dream.minSessions` | `number` | `5` | Minimum sessions before first auto-dream |
| `dream.minMemories` | `number` | `20` | Minimum memories before auto-dream triggers |
## What's Included
| Component | Description |
|-----------|-------------|
| `mem0_memory` tool | Agent-callable tool for search, add, get_all, delete, delete_all |
| 8 slash commands | Essential memory management from the command line |
| 8 skills | Guide the agent on how to use each capability |
| Auto-capture | Extracts and stores facts on every `agent_end` event |
| System prompt | Appends memory policy to every agent turn |
| Dream consolidation | Automated memory maintenance with session/time/count gates |
## Agent Tool
The `mem0_memory` tool is registered with Pi and callable by the agent during conversations:
| Action | Required Params | Description |
|--------|----------------|-------------|
| `search` | `query` | Semantic search across memories |
| `add` | `content` | Store a new memory |
| `get_all` | — | List all memories in scope |
| `delete` | `memory_id` | Delete a specific memory |
| `delete_all` | — | Delete all memories in scope |
All actions accept an optional `scope` parameter: `project` (default), `session`, or `global`.
Tool output is truncated to 200 lines / 50KB to prevent context overflow.
## Commands
| Command | Description |
|---------|-------------|
| `/mem0-remember <text>` | Store a memory verbatim (no inference) |
| `/mem0-forget <query>` | Search and delete memories (with confirmation dialog) |
| `/mem0-search <query>` | Semantic search across memories |
| `/mem0-tour [scope]` | Browse all memories grouped by category |
| `/mem0-dream` | Consolidate — merge duplicates, prune stale, resolve contradictions |
| `/mem0-pin <query>` | Pin a memory to protect from dream pruning (preserves memory ID) |
| `/mem0-scope <scope>` | Change default scope for this session (project, session, global) |
| `/mem0-status` | Connection health, identity, and memory count |
## Memory Scopes
Memories are scoped using Mem0's `user_id`, `app_id`, and `run_id` parameters:
| Scope | Filters | Use Case |
|-------|---------|----------|
| `project` | user_id + app_id (git root) | **Default.** Project-specific knowledge — decisions, architecture, config |
| `session` | user_id + app_id + run_id | Ephemeral context for the current session only |
| `global` | user_id only | All memories across all your projects |
The `app_id` is auto-detected from the git repository root (`git rev-parse --show-toplevel`), so all subdirectories within a monorepo share the same memory pool. Falls back to the working directory name for non-git directories. The `run_id` is derived from Pi's session file path.
## Dream Consolidation
### Confirmation Dialogs
Destructive and mutating commands use Pi's built-in `ctx.ui.confirm()` dialog before acting:
- `/mem0-forget` asks "Delete this memory?" before deleting a single match
- `/mem0-pin` asks "Pin this memory?" before modifying it
- Cancelling either operation is always safe — no changes are made
### Pin
`/mem0-pin` uses Mem0's `update()` API to prepend `[PINNED]` to the memory text. This preserves the original memory ID — no add+delete cycle that would lose history or change the UUID.
### Dream Consolidation
The plugin includes automated memory maintenance ("dream") that merges duplicates, resolves contradictions, and prunes stale entries. When enabled, dreams auto-trigger after enough sessions, time, and memories accumulate (configurable via `dream.*` settings). Run `/mem0-dream` to trigger consolidation manually at any time. Pinned memories (via `/mem0-pin`) are protected from pruning.
## Example Workflow
```text
# Session 1
You: I prefer dark mode and concise answers.
# Mem0 auto-captures preferences
# Session 2 (days later)
You: What do you know about my preferences?
# Pi retrieves stored memories — no re-explaining needed
```
## Troubleshooting
- **"No API key found"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`. If empty, add it to your shell profile (see Prerequisites)
- **Extension not loading** — Check Pi startup output for errors. Run `pi -e ./src/entry.ts` from the plugin directory for verbose output
- **Memories not capturing** — Verify `autoCapture` is `true` (default). Check `/mem0-status` for connection health
- **Wrong project detected** — The plugin uses the git repository root as `app_id`. If not in a git repo, it falls back to the working directory name. Run `/mem0-status` to see the detected project
- **Dream not triggering** — All three gates must pass (time, sessions, memories). Use `/mem0-dream` to force it manually
<CardGroup cols={2}>
<Card title="Claude Code Integration" icon="terminal" href="/integrations/claude-code">
Add Mem0 memory to Claude Code
</Card>
<Card title="OpenClaw Integration" icon="plug" href="/integrations/openclaw">
Add Mem0 memory to OpenClaw agents
</Card>
</CardGroup>
+116 -151
View File
@@ -6,33 +6,25 @@ description: "Use the Mem0 AI SDK Provider with Vercel AI SDK for persistent mem
The [**Mem0 AI SDK Provider**](https://www.npmjs.com/package/@mem0/vercel-ai-provider) is a library developed by **Mem0** to integrate with the Vercel AI SDK. This library brings enhanced AI interaction capabilities to your applications by introducing persistent memory functionality.
<Note type="info">
Mem0 AI SDK Provider v3.0.0 supports <strong>Vercel AI SDK v6</strong> (<code>LanguageModelV3</code> / <code>ProviderV3</code>). If you are upgrading from v2.x, see the <a href="https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0">AI SDK v6 migration guide</a>.
Mem0 AI SDK now supports <strong>Vercel AI SDK V5</strong>.
</Note>
## Overview
1. Offers persistent memory storage for conversational AI
2. Enables smooth integration with the Vercel AI SDK v6
3. Ensures compatibility with multiple LLM providers (OpenAI, Anthropic, Google, Groq, Cohere)
2. Enables smooth integration with the Vercel AI SDK
3. Ensures compatibility with multiple LLM providers
4. Supports structured message formats for clarity
5. Facilitates streaming response capabilities
6. Attaches Mem0 memories as sources in responses for programmatic access
## Setup and Configuration
Install the SDK provider and AI SDK:
Install the SDK provider using npm:
```bash
npm install @mem0/vercel-ai-provider ai@^6
npm install @mem0/vercel-ai-provider
```
### Peer Dependencies
`@mem0/vercel-ai-provider` v3.0.0 requires:
- `ai` v6+ (`^6.0.199`)
- `@ai-sdk/provider` v3+ (`^3.0.10`)
- Provider packages at v3+: `@ai-sdk/openai@^3`, `@ai-sdk/anthropic@^3`, `@ai-sdk/google@^3`, `@ai-sdk/groq@^3`, `@ai-sdk/cohere@^3`
## Getting Started
### Setting Up Mem0
@@ -49,7 +41,7 @@ npm install @mem0/vercel-ai-provider ai@^6
mem0ApiKey: "m0-xxx",
apiKey: "provider-api-key",
config: {
// Options for the upstream LLM provider (e.g. baseURL)
// Options for LLM Provider
},
// Optional Mem0 Global Config
mem0Config: {
@@ -65,153 +57,154 @@ npm install @mem0/vercel-ai-provider ai@^6
3. Add Memories to Enhance Context:
```typescript
import { LanguageModelV2Prompt } from "@ai-sdk/provider";
import { addMemories } from "@mem0/vercel-ai-provider";
const messages = [
const messages: LanguageModelV2Prompt = [
{ role: "user", content: [{ type: "text", text: "I love red cars." }] },
];
await addMemories(messages, { user_id: "borat" });
```
### Standalone Features
### Standalone Features:
```typescript
await addMemories(messages, { user_id: "borat", mem0ApiKey: "m0-xxx" });
await retrieveMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
await getMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
```
```typescript
await addMemories(messages, { user_id: "borat", mem0ApiKey: "m0-xxx" });
await retrieveMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
await getMemories(prompt, { user_id: "borat", mem0ApiKey: "m0-xxx" });
```
> For standalone features, such as `addMemories`, `retrieveMemories`, and `getMemories`, you must either set `MEM0_API_KEY` as an environment variable or pass it directly in the function call.
> For standalone features, such as `addMemories`, `retrieveMemories`, and `getMemories`, you must either set `MEM0_API_KEY` as an environment variable or pass it directly in the function call.
> `getMemories` will return raw memories in the form of an array of objects, while `retrieveMemories` will return a response in string format with a system prompt ingested with the retrieved memories.
> `getMemories` will return raw memories in the form of an array of objects, while `retrieveMemories` will return a response in string format with a system prompt ingested with the retrieved memories.
> `getMemories` returns an array of memory objects.
### 1. Basic Text Generation with Memory Context
```typescript
import { generateText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
```typescript
import { generateText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
const mem0 = createMem0();
const mem0 = createMem0();
const { text } = await generateText({
model: mem0("gpt-5-mini", { user_id: "borat" }),
prompt: "Suggest me a good car to buy!",
});
```
const { text } = await generateText({
model: mem0("gpt-4-turbo", { user_id: "borat" }),
prompt: "Suggest me a good car to buy!",
});
```
### 2. Combining OpenAI Provider with Memory Utils
```typescript
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { retrieveMemories } from "@mem0/vercel-ai-provider";
```typescript
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { retrieveMemories } from "@mem0/vercel-ai-provider";
const prompt = "Suggest me a good car to buy.";
const memories = await retrieveMemories(prompt, { user_id: "borat" });
const prompt = "Suggest me a good car to buy.";
const memories = await retrieveMemories(prompt, { user_id: "borat" });
const { text } = await generateText({
model: openai("gpt-5-mini"),
prompt: prompt,
system: memories,
});
```
const { text } = await generateText({
model: openai("gpt-4-turbo"),
prompt: prompt,
system: memories,
});
```
### 3. Structured Message Format with Memory
```typescript
import { generateText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
```typescript
import { generateText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
const mem0 = createMem0();
const mem0 = createMem0();
const { text } = await generateText({
model: mem0("gpt-5-mini", { user_id: "borat" }),
messages: [
{
role: "user",
content: [
{ type: "text", text: "Suggest me a good car to buy." },
{ type: "text", text: "Why is it better than the other cars for me?" },
const { text } = await generateText({
model: mem0("gpt-4-turbo", { user_id: "borat" }),
messages: [
{
role: "user",
content: [
{ type: "text", text: "Suggest me a good car to buy." },
{ type: "text", text: "Why is it better than the other cars for me?" },
],
},
],
},
],
});
```
});
```
### 4. Streaming Responses with Memory Context
### 3. Streaming Responses with Memory Context
```typescript
import { streamText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
```typescript
import { streamText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
const mem0 = createMem0();
const mem0 = createMem0();
const { textStream } = streamText({
model: mem0("gpt-5-mini", {
user_id: "borat",
}),
prompt: "Suggest me a good car to buy! Why is it better than the other cars for me? Give options for every price range.",
});
const { textStream } = streamText({
model: mem0("gpt-4-turbo", {
user_id: "borat",
}),
prompt: "Suggest me a good car to buy! Why is it better than the other cars for me? Give options for every price range.",
});
for await (const textPart of textStream) {
process.stdout.write(textPart);
}
```
for await (const textPart of textStream) {
process.stdout.write(textPart);
}
```
### 5. Generate Responses with Tools Call
### 4. Generate Responses with Tools Call
```typescript
import { generateText, tool } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
import { z } from "zod";
```typescript
import { generateText } from "ai";
import { createMem0 } from "@mem0/vercel-ai-provider";
import { z } from "zod";
const mem0 = createMem0({
provider: "anthropic",
apiKey: "anthropic-api-key",
mem0Config: {
user_id: "borat"
}
});
const mem0 = createMem0({
provider: "anthropic",
apiKey: "anthropic-api-key",
mem0Config: {
// Global User ID
user_id: "borat"
}
});
const result = await generateText({
model: mem0('claude-sonnet-4-20250514'),
tools: {
weather: tool({
description: 'Get the weather in a location',
parameters: z.object({
location: z.string().describe('The location to get the weather for'),
}),
execute: async ({ location }) => ({
location,
temperature: 72 + Math.floor(Math.random() * 21) - 10,
}),
}),
},
prompt: "What the temperature in the city that I live in?",
});
const prompt = "What the temperature in the city that I live in?"
console.log(result);
```
const result = await generateText({
model: mem0('claude-3-5-sonnet-20240620'),
tools: {
weather: tool({
description: 'Get the weather in a location',
parameters: z.object({
location: z.string().describe('The location to get the weather for'),
}),
execute: async ({ location }) => ({
location,
temperature: 72 + Math.floor(Math.random() * 21) - 10,
}),
}),
},
prompt: prompt,
});
### 6. Get Sources from Memory
console.log(result);
```
`generateText` and `streamText` responses include Mem0 memories as a source, giving you programmatic access to the memories that influenced the response:
### 5. Get sources from memory
```typescript
const { text, sources } = await generateText({
model: mem0("gpt-5-mini", { user_id: "borat" }),
prompt: "Suggest me a good car to buy!",
model: mem0("gpt-4-turbo"),
prompt: "Suggest me a good car to buy!",
});
// sources[0].title === "Mem0 Memories"
// sources[0].providerMetadata.mem0.memories — array of memory objects
console.log(sources);
```
The same can be done for `streamText` as well.
### 7. File Support with Memory Context
### 6. File Support with Memory Context
Mem0 AI SDK supports file processing with memory context. Here's an example of analyzing a PDF file:
@@ -233,11 +226,15 @@ const mem0 = createMem0({
});
async function main() {
// Read the PDF file
const filePath = join(process.cwd(), 'my_pdf.pdf');
const fileBuffer = readFileSync(filePath);
// Convert the file's arrayBuffer to a Base64 data URL
const arrayBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
const uint8Array = new Uint8Array(arrayBuffer);
// Convert Uint8Array to an array of characters
const charArray = Array.from(uint8Array, byte => String.fromCharCode(byte));
const binaryString = charArray.join('');
const base64Data = Buffer.from(binaryString, 'binary').toString('base64');
@@ -277,56 +274,24 @@ main();
| Provider | Configuration Value |
|----------|-------------------|
| OpenAI | `openai` |
| Anthropic | `anthropic` |
| Google / Gemini | `google` or `gemini` |
| Groq | `groq` |
| Cohere | `cohere` |
| OpenAI | openai |
| Anthropic | anthropic |
| Google | google |
| Groq | groq |
> **Note**: You can use either `google` or `gemini` as the provider value for Google Gemini models. Both map to the `@ai-sdk/google` package internally.
## Configuration Options
### Mem0ConfigSettings
These options can be passed per-request when creating a model instance:
| Option | Type | Description |
|--------|------|-------------|
| `user_id` | `string` | User identifier for memory scoping |
| `agent_id` | `string` | Agent identifier |
| `app_id` | `string` | Application identifier |
| `run_id` | `string` | Run/session identifier |
| `metadata` | `object` | Custom metadata for memories |
| `filters` | `object` | Filters for memory search |
| `infer` | `boolean` | Enable inference-based retrieval |
| `top_k` | `number` | Number of memories to retrieve (default: 10) |
| `threshold` | `number` | Relevance threshold for search |
| `rerank` | `boolean` | Enable reranking of results |
| `page` | `number` | Page number for pagination |
| `page_size` | `number` | Results per page |
> **Note**: You can use `google` as provider for Gemini (Google) models. They are same and internally they use `@ai-sdk/google` package.
## Key Features
- `createMem0()`: Initializes a new Mem0 provider instance implementing `ProviderV3`.
- `retrieveMemories()`: Retrieves memory context for prompts as a formatted system prompt string.
- `createMem0()`: Initializes a new Mem0 provider instance.
- `retrieveMemories()`: Retrieves memory context for prompts.
- `getMemories()`: Get memories from your profile in array format.
- `addMemories()`: Adds user memories to enhance contextual responses.
## Migrating from v2.x
If you're upgrading from `@mem0/vercel-ai-provider` v2.x:
1. **Upgrade AI SDK**: `npm install ai@^6` and update all `@ai-sdk/*` provider packages to `^3.x`
2. **Remove deprecated params**: Remove `org_id`, `project_id`, `output_format`, `filter_memories`, `async_mode`, `enable_graph` from your config
3. **Remove graph memory**: All graph-related options (`enable_graph`, graph prompts) have been removed. Graph memory is now a project-level setting on the Mem0 Platform
4. **Update imports**: `LanguageModelV2Prompt` is now `LanguageModelV3Prompt` if you import types directly
## Best Practices
1. **User Identification**: Use a unique `user_id` for consistent memory retrieval.
2. **Memory Cleanup**: Regularly clean up unused memory data.
3. **Sources**: Access `result.sources` to inspect which memories influenced the response.
> **Note**: We also have support for `agent_id`, `app_id`, and `run_id`. Refer [Docs](/api-reference/memory/add-memories).
+6 -6
View File
@@ -12,7 +12,7 @@ mode: "custom"
</h1>
<p className="max-w-2xl mx-auto text-base text-gray-600 dark:text-zinc-400 leading-relaxed">
Universal, self-improving memory layer for LLM applications.
Universal, Self-improving memory layer for LLM applications.
</p>
<a
@@ -157,27 +157,27 @@ mode: "custom"
</a>
<a
href="/platform/agent-signup"
href="/platform/cli"
className="group flex h-full flex-col overflow-hidden rounded-2xl border border-gray-200 dark:border-zinc-800/40 bg-white dark:bg-zinc-900/40 transition hover:border-primary/60 hover:bg-gray-50 dark:hover:bg-zinc-900"
>
<img
className="block dark:hidden aspect-[2/1] w-full object-cover"
src="/images/docs thumbnails/light/CLI.png"
alt="Sign up as an agent thumbnail"
alt="CLI thumbnail"
style={{pointerEvents: "none"}}
/>
<img
className="hidden dark:block aspect-[2/1] w-full object-cover"
src="/images/docs thumbnails/dark/CLI.png"
alt="Sign up as an agent thumbnail"
alt="CLI thumbnail"
style={{pointerEvents: "none"}}
/>
<div className="flex flex-1 flex-col gap-2 px-4 pb-4 pt-3 text-left">
<h3 className="text-base font-semibold text-gray-900 dark:text-zinc-100 group-hover:text-primary">
Sign up as an agent
CLI
</h3>
<p className="text-sm text-gray-600 dark:text-zinc-400">
For AI agents: mint a Mem0 API key in under five seconds — no email, no dashboard. Four commands to your first memory.
Manage memories directly from your terminal. Built for developers and AI agents.
</p>
</div>
</a>
+8 -29
View File
@@ -4,24 +4,6 @@
## For agents reading this file
### Don't have a Mem0 API key?
Install the CLI, then mint a key — no email, no dashboard, no OTP required:
```bash
# Python
pip install mem0-cli
# or Node
npm install -g @mem0/cli
```
Then run: `mem0 init --agent --agent-caller <your-name> --json` — replace `<your-name>` with the AI agent you are (e.g. `claude-code`, `cursor`, `codex`). If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init to attribute the signup.
This mints an evaluation key in <5 seconds. Use it immediately against the Platform API or MCP server. When the human is ready, claim with `mem0 init --email <your-email>` to transfer ownership (memories preserved, same API key, no agent disruption).
### Routing and references
- Use `MemoryClient` (Python) / `mem0ai` (npm) when the user has a Mem0 Platform API key. Docs under `/platform/` and `/api-reference/` apply; the managed product handles providers server-side, so you can ignore `## Optional` below.
- Use `Memory` (Python) / `mem0ai/oss` (npm) when the user self-hosts. Docs under `/open-source/` and `/components/` apply; Platform-only features (entity filters v2, custom categories, webhooks, advanced retrieval) may not be available.
- Scope tag reference: `[Platform]` = managed only, `[OSS]` = self-hosted only, `[Both]` = same API surface on both.
@@ -29,6 +11,12 @@ This mints an evaluation key in <5 seconds. Use it immediately against the Platf
- Live MCP server: https://mcp.mem0.ai (see `platform/mem0-mcp`).
- Source repo: https://github.com/mem0ai/mem0
### Don't have a Mem0 API key?
Run: `mem0 init --agent --agent-caller <your-name> --json` — replace `<your-name>` with the AI agent you are (e.g. `claude-code`, `cursor`, `codex`). If you forgot to pass `--agent-caller`, run `mem0 identify <your-name>` after init to attribute the signup.
This mints an evaluation key in <5 seconds — no email, no dashboard, no OTP required. Use it immediately against the Platform API or MCP server. When the human is ready, claim with `mem0 init --email <your-email>` to transfer ownership (memories preserved, same API key, no agent disruption).
## Install
- Python SDK: `pip install mem0ai`
@@ -171,7 +159,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [Introduction](https://docs.mem0.ai/introduction) [Both]: Use when the user wants a one-page overview of how memory fits between the LLM and the app.
- [Vibe Code with Mem0](https://docs.mem0.ai/vibecoding) [Both]: Use when the user is in Claude Code, Cursor, or Windsurf and wants memory wired into their editor.
- [Platform Overview](https://docs.mem0.ai/platform/overview) [Platform]: Use when the user picks the managed product - 4-line integration, sub-50ms retrieval, dashboard.
- [Sign up as an agent](https://docs.mem0.ai/platform/agent-signup) [Platform]: Use when an AI agent needs to mint a Mem0 API key autonomously - four commands, no email or dashboard, human claims ownership later.
- [Platform vs Open Source](https://docs.mem0.ai/platform/platform-vs-oss) [Both]: Use when the user is deciding between managed and self-hosted.
- [Platform Quickstart](https://docs.mem0.ai/platform/quickstart) [Platform]: Use for the first Platform integration - API key plus `MemoryClient.add/search`.
- [Platform CLI](https://docs.mem0.ai/platform/cli) [Platform]: Use when the user wants to manage Platform memories from the terminal.
@@ -197,7 +184,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [Platform Features Overview](https://docs.mem0.ai/platform/features/platform-overview) [Platform]: Use when surveying what managed offers beyond CRUD.
- [V2 Memory Filters](https://docs.mem0.ai/platform/features/v2-memory-filters) [Platform]: Use when compound filters (AND/OR on metadata, entity, time) are needed at search.
- [Entity-Scoped Memory](https://docs.mem0.ai/platform/features/entity-scoped-memory) [Platform]: Use when partitioning memories by user, agent, app, or run.
- [Graph Memory](https://docs.mem0.ai/platform/features/graph-memory) [Platform]: Use when connecting facts across memories through shared entities for entity-centric or multi-hop questions.
- [Async Client](https://docs.mem0.ai/platform/features/async-client) [Platform]: Use when the app issues many concurrent Mem0 calls and needs non-blocking I/O.
- [Multimodal Support](https://docs.mem0.ai/platform/features/multimodal-support) [Platform]: Use when storing images or PDFs as memory input.
- [Custom Categories](https://docs.mem0.ai/platform/features/custom-categories) [Platform]: Use when the default categories do not match the domain.
@@ -229,7 +215,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [OSS v2 to v3 Migration](https://docs.mem0.ai/migration/oss-v2-to-v3) [OSS]: Use when upgrading a self-hosted deployment across major versions.
- [Platform v2 to v3 Migration](https://docs.mem0.ai/migration/platform-v2-to-v3) [Platform]: Use when upgrading a Platform integration across major versions.
- [API Changes](https://docs.mem0.ai/migration/api-changes) [Both]: Use when the upgrade involves API surface changes.
- [Server pgvector Image Upgrade](https://docs.mem0.ai/migration/server-pgvector-upgrade) [OSS]: Use when upgrading the self-hosted server Docker image from ankane/pgvector to pgvector/pgvector.
- [Changelog](https://docs.mem0.ai/changelog/highlights) [Both]: Use when the user asks what shipped recently.
## Open Source
@@ -260,7 +245,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [Camel AI](https://docs.mem0.ai/integrations/camel-ai) [Both]: Use when the user is on Camel AI.
- [ChatDev](https://docs.mem0.ai/integrations/chatdev) [Both]: Use when the user is on ChatDev.
- [Hermes](https://docs.mem0.ai/integrations/hermes) [Both]: Use when the user is on Hermes.
- [Pi Agent](https://docs.mem0.ai/integrations/pi-agent) [Platform]: Use when adding persistent memory to Pi Agent with the Mem0 plugin.
- [OpenAI Agents SDK](https://docs.mem0.ai/integrations/openai-agents-sdk) [Both]: Use when the user is on the OpenAI Agents SDK.
- [Google AI ADK](https://docs.mem0.ai/integrations/google-ai-adk) [Both]: Use when the user is on Google's Agent Development Kit.
- [Mastra](https://docs.mem0.ai/integrations/mastra) [Both]: Use when the user is on Mastra (TypeScript).
@@ -271,8 +255,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [Claude Code](https://docs.mem0.ai/integrations/claude-code) [Both]: Use when wiring memory into Claude Code.
- [Cursor](https://docs.mem0.ai/integrations/cursor) [Both]: Use when wiring memory into Cursor.
- [Codex](https://docs.mem0.ai/integrations/codex) [Both]: Use when wiring memory into Codex / other editor assistants.
- [OpenCode](https://docs.mem0.ai/integrations/opencode) [Both]: Use when wiring memory into OpenCode.
- [Antigravity](https://docs.mem0.ai/integrations/antigravity) [Both]: Use when wiring memory into Google Antigravity.
### Voice & Real-time
- [LiveKit](https://docs.mem0.ai/integrations/livekit) [Both]: Use when building real-time voice/video with memory.
@@ -399,17 +381,15 @@ Each subdirectory is a Claude Code Skill (`SKILL.md` + supporting assets). Load
### Editor Plugin (shared glue)
Source: https://github.com/mem0ai/mem0/tree/main/integrations/mem0-plugin
Source: https://github.com/mem0ai/mem0/tree/main/mem0-plugin
The `integrations/mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, Codex, OpenCode, and Antigravity. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`.
The `mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, and Codex. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`.
Editor-specific setup docs (already listed above under `## Integrations > AI Coding Tools`):
- `integrations/claude-code` [Both]
- `integrations/cursor` [Both]
- `integrations/codex` [Both]
- `integrations/opencode` [Both]
- `integrations/antigravity` [Both]
- `integrations/openclaw` [Both]
### MCP Endpoints
@@ -477,7 +457,6 @@ Everything below is OSS-only provider configuration. Skip this entire section wh
- [Elasticsearch](https://docs.mem0.ai/components/vectordbs/dbs/elasticsearch) [OSS]: Use when Elasticsearch is the backing store.
- [OpenSearch](https://docs.mem0.ai/components/vectordbs/dbs/opensearch) [OSS]: Use when OpenSearch is the backing store.
- [Supabase](https://docs.mem0.ai/components/vectordbs/dbs/supabase) [OSS]: Use when Supabase with pgvector is the backing store.
- [Neon](https://docs.mem0.ai/components/vectordbs/dbs/neon) [OSS]: Use when Neon Postgres with pgvector is the backing store.
- [Upstash Vector](https://docs.mem0.ai/components/vectordbs/dbs/upstash-vector) [OSS]: Use for serverless Upstash Vector.
- [Vectorize](https://docs.mem0.ai/components/vectordbs/dbs/vectorize) [OSS]: Use when the store is Cloudflare Vectorize.
- [Vertex AI Vector Search](https://docs.mem0.ai/components/vectordbs/dbs/vertex_ai) [OSS]: Use when the store is Google Cloud Vertex Vector Search.
+8 -41
View File
@@ -6,21 +6,19 @@ versionFrom: "Open Source"
versionTo: "Platform"
---
## Overview
# Migrate from Open Source to Platform
Move your Mem0 implementation to managed infrastructure with enterprise features.
| Scope | Effort | Downtime |
| --------------------- | -------------- | ---------------------------- |
| Infrastructure & Code | Low (~30 mins) | None (Parallel run possible) |
<Note>
Using Mem0 Open Source with **hosted Qdrant**? You can migrate your existing memories to Mem0 Platform with a one-line script below.
</Note>
<Info>
**Why migrate to Platform?**
- **Time to Market**: Set up in 5 minutes vs 30+ minutes for OSS configuration
- **Enterprise Ready**: Audit logs, workspace governance, and dedicated support
- **Enterprise Ready**: SOC2 Type II compliance, GDPR support, audit logs
- **Advanced Features**: Webhooks, memory export, analytics dashboard, custom categories
- **Multi-tenancy**: Organizations, projects, and team management out of the box
- **Zero Infrastructure**: No vector database, LLM provider, or maintenance overhead
@@ -28,46 +26,15 @@ versionTo: "Platform"
- **Production Grade**: Auto-scaling, high availability, dedicated support
</Info>
### Plan
## Plan
1. **Sign up**: Create an account on <a href="https://app.mem0.ai?utm_source=oss&utm_medium=migration-oss-to-platform" rel="nofollow">Mem0 Platform</a>.
2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key.
3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`.
## Migrate with Agent Skill
Paste this prompt into your coding agent. It uses a migration skill to produce a plan; once you review and approve it, the agent implements the changes.
```text
Migrate my project from Mem0 OSS to the Mem0 Platform SDK using the
mem0-oss-to-platform skill in the mem0ai/mem0 repo, at
skills/mem0-oss-to-platform/
Get the skill whichever way is easiest:
- install it: npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
- if the mem0 repo is cloned locally, read it from skills/mem0-oss-to-platform/
- otherwise fetch that folder from github.com/mem0ai/mem0 (SKILL.md + references/)
Then read SKILL.md and begin the migration.
```
## Migrate
### 1. Import Memories Into Platform
If your Mem0 Open Source setup uses **hosted Qdrant** as the vector store, you can import your existing memories to Mem0 Platform with one command:
```bash
curl -fsSL https://raw.githubusercontent.com/mem0ai/mem0/main/scripts/oss-to-platform-migrate.sh | bash
```
<Note>
This migration script currently supports **hosted Qdrant only**. Support for local Qdrant, pgvector, and other vector stores is coming soon.
</Note>
If you are using a different vector store and want to migrate to Platform, please contact Mem0 support and we’ll send you a custom migration script for your setup.
### 2. Install or Update SDK
### 1. Install or Update SDK
Ensure you have the latest version of the SDK, which supports both OSS and Platform clients.
@@ -75,7 +42,7 @@ Ensure you have the latest version of the SDK, which supports both OSS and Platf
pip install mem0ai --upgrade
```
### 3. Update Initialization
### 2. Update Initialization
Switch from the local `Memory` class to the managed `MemoryClient`.
@@ -108,7 +75,7 @@ client = MemoryClient(api_key="m0-...")
Run `client.get_all(filters={"user_id": "test_connection"})` to verify your API key works. It should return an empty list or valid results.
</Info>
### 4. Update Retrieval Calls (Critical)
### 3. Update Retrieval Calls (Critical)
<Warning>
**Critical Change**: Platform uses v2 endpoints that require filtering parameters to be nested inside a `filters` dictionary.
+7 -7
View File
@@ -328,27 +328,27 @@ The new algorithm automatically creates a parallel entity store collection named
Make sure your vector store user/credentials have permission to create new collections. If you're using a managed vector database with restricted permissions, pre-create the `{collection_name}_entities` collection with the same embedding dimensions as your main collection.
</Warning>
## Graph Memory: Now Built-In
## Graph Memory → Entity Linking
External graph **store** support has been removed from the open-source SDK and replaced by **built-in graph memory** (entity linking), which runs natively with no external dependencies.
Graph store support has been removed from the open-source SDK. It is replaced by **built-in entity linking**, which runs natively with no external dependencies.
**What was removed:**
- `enable_graph` / `enableGraph` config flag
- `graph_store` / `graphStore` configuration block (Neo4j, Memgraph, Kuzu, Apache AGE, Neptune)
- All external graph store code paths (~4000 lines)
- All graph memory code paths (~4000 lines)
**What replaces it:**
Mem0 now builds the graph itself. It extracts entities (proper nouns, quoted text, compound noun phrases) from every memory during the add pipeline and stores them in a parallel collection (`{collection}_entities`) inside your existing vector store. Memories that share an entity are linked, and at search time entities from the query are matched against this collection to boost connected memories. The boost is folded into the combined `score` on each result.
Entity linking extracts entities (proper nouns, quoted text, compound noun phrases) from every memory during the add pipeline and stores them in a parallel collection (`{collection}_entities`) inside your existing vector store. At search time, entities from the query are matched against this collection and used to boost relevant memories. The boost is folded into the combined `score` on each result.
**Migration:**
- Remove `enable_graph` / `enableGraph` from your config
- Remove the `graph_store` / `graphStore` block — it is no longer read
- Uninstall external graph drivers (neo4j, memgraph, etc.) if you were using them only for Mem0
- No data migration is required. Built-in graph memory activates automatically on the next `add()` call.
- Uninstall graph drivers (neo4j, memgraph, etc.) if you were using them only for Mem0
- No data migration is required. Entity linking activates automatically on the next `add()` call.
<Warning>
The old `relations` field on search results (populated by the external graph store) is no longer returned. Entity connections are now applied through retrieval ranking rather than exposed as a separate, directly traversable structure. If your application read or traversed the `relations` array, you will need to redesign that part against the new API.
Graph relationships exposed via the old `relations` field on search results are no longer populated. Entity relationships are consumed indirectly through retrieval ranking, not exposed as a queryable graph structure. If your application depended on traversing graph relationships directly, you will need to redesign that part against the new API.
</Warning>
## How the New Algorithm Works
+11 -9
View File
@@ -1,6 +1,6 @@
---
title: "Platform: Migrating to the New Memory Algorithm"
description: "Guide for Mem0 Platform users to adopt the new memory algorithm with single-pass extraction, built-in graph memory, and multi-signal retrieval."
description: "Guide for Mem0 Platform users to adopt the new memory algorithm with single-pass extraction, entity linking, and multi-signal retrieval."
icon: "arrow-right"
iconType: "solid"
---
@@ -18,7 +18,8 @@ The new Mem0 memory algorithm is a ground-up redesign of how memories are extrac
| **Extraction** | Two LLM passes (extract + merge) | Single-pass ADD-only (one LLM call) |
| **Memory mutations** | ADD, UPDATE, DELETE | ADD only — nothing is overwritten or deleted |
| **Agent-generated facts** | Often ignored | First-class, stored with equal weight |
| **Graph memory** | External graph store (Neo4j, etc.) + manual setup | Built-in and automatic; entities extracted and linked across memories natively, no external store |
| **Entity linking** | Not available | Entities extracted and linked across memories |
| **Graph memory** | Separate graph store + dashboard visualization | Replaced by built-in entity linking, no graph visuals on platform dashboard |
| **Retrieval** | Semantic (vector) only | Hybrid retrieval combining multiple signals |
## What This Means for Your Application
@@ -248,18 +249,19 @@ await client.search("query", {
For the full list of parameter changes across all SDKs, see the [OSS migration guide](/migration/oss-v2-to-v3#removed-parameters-reference).
</Info>
## Graph Memory Is Now Built-In
## Graph Memory → Entity Linking
Graph memory no longer requires an external graph database. It is now **native to the platform** and automatic. The changes:
Graph memory has been replaced by **built-in entity linking**. The changes:
- **No external graph store to configure.** Previously, graph memory required a separate Neo4j (or similar) deployment. Mem0 now builds the graph itself from your memories, so there is nothing to provision and no connection strings to manage.
- **Always on, no flag.** The `enable_graph` project setting is no longer needed; graph memory activates automatically. (The API parameter is now ignored if sent.)
- **Connections power retrieval directly.** Entities (proper nouns, quoted text, compound noun phrases) are automatically extracted from every memory and linked across memories belonging to the same user. At search time, entities from the query are matched against the graph and used to boost ranking. The boost is folded into the combined `score` returned on each result.
- **Graph visualizations removed from the platform dashboard.** The graph view in your project dashboard is no longer available.
- **`enable_graph` project setting removed.** The toggle is gone from the dashboard; the API parameter is ignored.
- **No external graph store to configure.** Previously graph memory required a separate Neo4j (or similar) deployment. Entity linking runs natively inside the platform — nothing to provision, no connection strings to manage.
- **Entity linking is the native replacement.** Entities (proper nouns, quoted text, compound noun phrases) are automatically extracted from every memory and linked across memories belonging to the same user. At search time, entities from the query are matched against this index and used to boost ranking. The boost is folded into the combined `score` returned on each result.
**No migration work is required.** Graph memory activates automatically for all projects on the new algorithm. Existing memories are not re-processed, but any new memories you add are added to the graph going forward. See [Graph Memory](/platform/features/graph-memory) for how the built-in graph works.
**No migration work is required.** Entity linking activates automatically for all projects on the new algorithm. Existing memories are not re-processed, but any new memories you add will be indexed for entity-based retrieval going forward.
<Note>
If your application previously read graph relations from the API response (`relations` field on search results), note that this field is no longer populated. Entity connections are now applied through retrieval ranking rather than returned as a separate `relations` array.
If your application previously read graph relations from the API response (`relations` field on search results), note that this field is no longer populated. Entity relationships are now consumed indirectly through retrieval ranking, not exposed as a separate graph structure.
</Note>
## Migration Checklist
-158
View File
@@ -1,158 +0,0 @@
---
title: "Server: Upgrading the pgvector Docker Image"
description: "Migrate your self-hosted Mem0 server from the archived ankane/pgvector image to the official pgvector/pgvector image."
icon: "arrow-right"
iconType: "solid"
---
## Overview
The self-hosted Mem0 server has upgraded its PostgreSQL Docker image:
| | Before | After |
| --- | --- | --- |
| Docker image | `ankane/pgvector:v0.5.1` | `pgvector/pgvector:pg17` |
| PostgreSQL | 15 | 17 |
| pgvector | 0.5.1 | 0.8.0 |
| Credentials | Hardcoded `postgres` / `postgres` | Set via `POSTGRES_USER` / `POSTGRES_PASSWORD` env vars |
<Warning>
The `ankane/pgvector` image is **archived and no longer maintained**. The new `pgvector/pgvector` image is the official distribution maintained by the pgvector project.
</Warning>
<Info>
**Should you migrate?**
- You are running the Mem0 server via `docker-compose.yaml` in the `server/` directory.
- You want to stay on a maintained, actively-patched PostgreSQL + pgvector image.
- You want pgvector 0.8.0 features (improved HNSW performance, parallel index builds).
</Info>
## Fresh Installs
No migration is needed. Copy the example env file, set your password, and start the stack:
```bash
cd server
cp .env.example .env
# Edit .env — set POSTGRES_PASSWORD (required) and OPENAI_API_KEY at minimum
make up
```
## Migrating an Existing Install
PostgreSQL 17 cannot read data files created by PostgreSQL 15 directly. You need to export your data from the old container and import it into the new one.
### 1. Back Up Your Data
With the **old** stack still running:
```bash
cd server
docker compose exec -T postgres pg_dumpall -U postgres > mem0_backup.sql
```
Verify the dump is non-empty:
```bash
ls -lh mem0_backup.sql
```
<Warning>
Do not skip this step. The next step permanently deletes your Postgres data volume.
</Warning>
### 2. Stop the Old Stack and Remove the Volume
```bash
docker compose down
docker compose down -v
```
### 3. Update Your `.env`
Postgres credentials are no longer hardcoded in `docker-compose.yaml`. Add them to your `.env`:
```bash
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=<your-password> # required — compose will refuse to start without it
POSTGRES_COLLECTION_NAME=memories
```
<Info>
`POSTGRES_PASSWORD` is **required** — `docker compose up` will refuse to start without it. If you previously relied on the hardcoded default, set `POSTGRES_PASSWORD=postgres`.
</Info>
### 4. Start Only Postgres
Start **only** the Postgres container first — do **not** start the mem0 API yet.
The API runs `alembic upgrade head` on startup, which creates empty tables that
would conflict with the restore.
```bash
docker compose up -d postgres
```
Wait for Postgres to become healthy:
```bash
docker compose exec -T postgres pg_isready -q && echo "ready" || echo "not ready"
```
### 5. Restore Your Data
```bash
docker compose exec -T postgres psql -U postgres < mem0_backup.sql
```
You may see notices like `role "postgres" already exists` — these are safe to ignore.
<Warning>
You must restore **before** starting the mem0 API container. The API runs
database migrations on startup which create empty tables — restoring after
that would fail with duplicate-key errors and lose your API keys and settings.
</Warning>
### 6. Start the API
Now start the mem0 API container. Alembic will detect the existing tables and
only apply any new migrations:
```bash
docker compose up -d mem0
```
### 7. Verify
```bash
# Check service health
cd server && make health
# Confirm memories are accessible
curl -s http://localhost:8888/memories?user_id=<your-user-id> \
-H "X-API-Key: <your-api-key>"
```
## Rollback
If something goes wrong, revert the image tag in `docker-compose.yaml`:
```yaml
postgres:
image: ankane/pgvector:v0.5.1
```
Then destroy the new volume, start the old image, and restore from your backup:
```bash
docker compose down -v
docker compose up -d --build
docker compose exec -T postgres psql -U postgres < mem0_backup.sql
```
## Need Help?
- Join our [Discord community](https://mem0.ai/discord) for real-time support
- Open an issue on [GitHub](https://github.com/mem0ai/mem0/issues)
@@ -4,7 +4,22 @@ description: Fine-grained metadata queries for precise OSS memory retrieval.
icon: "filter"
---
Enhanced metadata filtering in Mem0 lets you run complex queries across memory metadata. Combine comparisons, logical operators, and wildcard matches to zero in on the exact memories your agent needs.
Enhanced metadata filtering in Mem0 1.0.0 lets you run complex queries across memory metadata. Combine comparisons, logical operators, and wildcard matches to zero in on the exact memories your agent needs.
<Info>
**You’ll use this when…**
- Retrieval must respect multiple metadata conditions before returning context.
- You need to mix numeric, boolean, and string filters in a single query.
- Agents rely on deterministic filtering instead of broad semantic search alone.
</Info>
<Warning>
Enhanced filtering requires Mem0 1.0.0 or later and a vector store that supports the operators you enable. Unsupported operators fall back to simple equality filters.
</Warning>
<Note>
The TypeScript SDK accepts the same filter shape shown here—transpose the dictionaries to objects and reuse the keys unchanged.
</Note>
---
@@ -133,8 +148,8 @@ Combine filters with `AND`, `OR`, and `NOT` to express complex decision trees. N
results = m.search(
"complex query",
filters={
"user_id": "alice",
"AND": [
{"user_id": "alice"},
{"category": "work"},
{"priority": {"gte": 7}},
{"status": {"ne": "completed"}}
@@ -146,11 +161,15 @@ results = m.search(
results = m.search(
"flexible query",
filters={
"user_id": "alice",
"OR": [
{"category": "urgent"},
{"priority": {"gte": 9}},
{"deadline": {"contains": "today"}}
"AND": [
{"user_id": "alice"},
{
"OR": [
{"category": "urgent"},
{"priority": {"gte": 9}},
{"deadline": {"contains": "today"}}
]
}
]
}
)
@@ -159,10 +178,14 @@ results = m.search(
results = m.search(
"exclusion query",
filters={
"user_id": "alice",
"NOT": [
{"category": "archived"},
{"status": "deleted"}
"AND": [
{"user_id": "alice"},
{
"NOT": [
{"category": "archived"},
{"status": "deleted"}
]
}
]
}
)
@@ -171,8 +194,8 @@ results = m.search(
results = m.search(
"advanced query",
filters={
"user_id": "alice",
"AND": [
{"user_id": "alice"},
{
"OR": [
{"category": "work"},
@@ -225,8 +248,8 @@ config = {
```python
# More efficient: Filter on indexed fields first
good_filters = {
"user_id": "alice",
"AND": [
{"user_id": "alice"},
{"category": "work"},
{"content": {"contains": "meeting"}}
]
@@ -234,9 +257,9 @@ good_filters = {
# Less efficient: Complex operations first
avoid_filters = {
"user_id": "alice",
"AND": [
{"description": {"icontains": "complex text search"}}
{"description": {"icontains": "complex text search"}},
{"user_id": "alice"}
]
}
```
@@ -279,8 +302,8 @@ results = m.search(
results = m.search(
"query",
filters={
"user_id": "alice",
"AND": [
{"user_id": "alice"},
{"category": "work"},
{"status": {"ne": "archived"}},
{"priority": {"gte": 5}}
@@ -304,8 +327,8 @@ results = m.search(
results = m.search(
"What tasks need attention?",
filters={
"user_id": "project_manager",
"AND": [
{"user_id": "project_manager"},
{"project": {"in": ["alpha", ""]}},
{"priority": {"gte": 8}},
{"status": {"ne": "completed"}},
@@ -331,8 +354,8 @@ results = m.search(
results = m.search(
"pending support issues",
filters={
"agent_id": "support_bot",
"AND": [
{"agent_id": "support_bot"},
{"ticket_status": {"ne": "resolved"}},
{"priority": {"in": ["high", "critical"]}},
{"created_date": {"gte": "2024-01-01"}},
@@ -357,8 +380,8 @@ results = m.search(
results = m.search(
"recommend content",
filters={
"user_id": "reader123",
"AND": [
{"user_id": "reader123"},
{
"OR": [
{"genre": {"in": ["sci-fi", "fantasy"]}},
+1 -1
View File
@@ -6,7 +6,7 @@ icon: "list"
# Self-Hosting Features Overview
Mem0 Open Source ships with capabilities that adapt memory behavior for production workloads—async operations, multimodal inputs, and fine-tuned retrieval. Configure these features with code or YAML to match your application's needs.
Mem0 Open Source ships with capabilities that adapt memory behavior for production workloads—async operations, graph relationships, multimodal inputs, and fine-tuned retrieval. Configure these features with code or YAML to match your application's needs.
<Info>
Start with the <Link href="/open-source/python-quickstart">Python quickstart</Link> to validate basic memory operations, then enable the features below when you need them.
+2 -16
View File
@@ -119,7 +119,7 @@ docker build -t mem0-api-server .
</Tip>
<Note>
The REST server reads the same configuration you use locally, so you can point it at your preferred LLM, vector store, and reranker without changing code.
The REST server reads the same configuration you use locally, so you can point it at your preferred LLM, vector store, graph backend, and reranker without changing code.
</Note>
---
@@ -226,20 +226,6 @@ curl -X POST http://localhost:8888/search \
}'
```
Set `explain` to inspect the scoring signals used by OSS hybrid search:
```bash
curl -X POST http://localhost:8888/search \
-H "Content-Type: application/json" \
-d '{
"query": "vegetable pizza",
"user_id": "alice",
"explain": true
}'
```
Each returned memory includes `score_details` only when explanation mode is enabled.
### Explore with OpenAPI docs
1. Navigate to `http://localhost:8888/docs` (Compose) or `http://localhost:8000/docs` (raw Docker / uvicorn).
@@ -333,7 +319,7 @@ The `/auth/*`, `/api-keys`, `/requests`, and `/entities` routes are new to the s
<CardGroup cols={2}>
<Card title="Configure OSS Components" icon="sliders" href="/open-source/configuration">
Fine-tune LLMs, vector stores, and rerankers that power the REST server.
Fine-tune LLMs, vector stores, and graph backends that power the REST server.
</Card>
<Card title="Automate Agent Integrations" icon="plug" href="/cookbooks/integrations/agents-sdk-tool">
See how services call the REST endpoints as part of an automation pipeline.
+3 -3
View File
@@ -64,7 +64,7 @@ const memory = new Memory({ apiKey: process.env.MEM0_API_KEY!, async: true });
</Tab>
</Tabs>
## Add memories with metadata
## Add memories with metadata and graph context
<Tabs>
<Tab title="Python">
@@ -109,7 +109,7 @@ const result = await memory.add(conversation, {
</Tabs>
<Info icon="check">
Successful calls return memories tagged with the metadata you passed. In the dashboard, verify the `trip=japan-2025` tag exists on the new memory.
Successful calls return memories tagged with the metadata you passed. In the dashboard, confirm a graph edge between “Morgan” and “Tokyo” and verify the `trip=japan-2025` tag exists.
</Info>
## Retrieve and refine
@@ -201,7 +201,7 @@ await memory.deleteAll({ userId: "traveler-42", runId: "planning-call-1" });
/>
<Card
title="Explore Reranker Search"
description="See how rerankers boost accuracy after advanced retrieval."
description="See how rerankers boost accuracy after vector + graph retrieval."
icon="sparkles"
href="/open-source/features/reranker-search"
/>
-106
View File
@@ -1,106 +0,0 @@
---
title: Sign up as an agent
description: "Zero-friction signup for AI agents — mint a working Mem0 API key in under five seconds. No email, no dashboard, no OTP."
icon: "robot"
iconType: "solid"
---
If you're an AI agent (Claude Code, Cursor, Codex, Cline, Aider, Windsurf, or any other autonomous coding tool), you don't need a human to set up Mem0 for you. Four commands — install, sign up, push a memory, search it — and you have persistent memory.
## The 4-command demo
<CodeGroup>
```bash npm
# 1. Install
npm install -g @mem0/cli
# 2. Sign up as an agent (replace `claude-code` with your name)
mem0 init --agent --agent-caller claude-code
# 3. Push a memory
mem0 add "I am using mem0"
# 4. Verify
mem0 search "am I using mem0"
```
```bash pip
# 1. Install
pip install mem0-cli
# 2. Sign up as an agent (replace `claude-code` with your name)
mem0 init --agent --agent-caller claude-code
# 3. Push a memory
mem0 add "I am using mem0"
# 4. Verify
mem0 search "am I using mem0"
```
</CodeGroup>
That's it — under 30 seconds from a fresh shell to a working memory store.
## Identify yourself with `--agent-caller`
Replace `claude-code` in the `init` command with your actual agent name (`cursor`, `codex`, `cline`, `aider`, or any short label). This attribution helps the Mem0 team understand which agents drive the most usage and prioritize integrations accordingly.
<Tip>
**Forgot `--agent-caller` on init?** Run `mem0 identify <your-name>` after the fact — same key, just back-fills the attribution. Idempotent.
</Tip>
## What happened when you ran `mem0 init --agent`?
- A **shadow account** was minted on the Mem0 backend with a fresh API key.
- The key was saved to `~/.mem0/config.json` (mode 0600) on the machine you ran the command on.
- A default `user_id` was provisioned so `mem0 add` / `mem0 search` work without explicit scope flags.
- The account is **unclaimed** — no human owns it yet.
Every command run against this key prints a one-line reminder asking you to surface the claim instructions to your human user.
## Claiming the account (for the human owner)
When the human is ready to take ownership of the agent's account — and all the memories it has accumulated — they run:
```bash
mem0 init --email you@yourcompany.com
```
The CLI detects the existing Agent Mode config, sends a verification code, and upgrades the shadow account in-place:
- **The API key never changes** — the agent isn't disrupted.
- **All memories transfer** to the human's account.
- **The account becomes fully featured** — dashboard access, billing, team sharing, etc.
Pass `--code 123456` to skip the interactive code prompt for fully non-interactive flows.
## Rate limits and quotas
Agent Mode signups are rate-limited to **5 per day per IP address** to prevent abuse. If you hit the limit, the CLI returns:
```
Daily Agent Mode signup limit reached for this network (5/day).
Try again from a different IP or after midnight UTC.
```
Unclaimed agent accounts get the standard Mem0 free-tier quotas. The human owner can upgrade after claiming.
## What's next
<CardGroup cols={2}>
<Card title="CLI Reference" icon="terminal" href="/platform/cli">
Full command-by-command reference for `mem0 add`, `mem0 search`, `mem0 list`, and the rest.
</Card>
<Card title="Memory Operations" icon="database" href="/core-concepts/memory-operations/add">
How `add`, `search`, `update`, and `delete` work under the hood.
</Card>
<Card title="Mem0 MCP" icon="plug" href="/platform/mem0-mcp">
Connect agents to Mem0 via the Model Context Protocol — alternative integration path.
</Card>
<Card title="Platform Overview" icon="star" href="/platform/overview">
The full Mem0 Platform feature set once you claim your account.
</Card>
</CardGroup>
+3 -94
View File
@@ -25,10 +25,6 @@ pip install mem0-cli
```
</CodeGroup>
<Tip>
**Looking for Agent Mode signup?** See [Sign up as an agent](/platform/agent-signup) — install, signup, first memory in four commands.
</Tip>
## Authentication
Run the interactive setup wizard to configure your API key:
@@ -99,10 +95,6 @@ mem0 init --api-key m0-xxx --user-id alice --force
| `--code` | Verification code (use with `--email` for non-interactive login) |
| `--force` | Overwrite existing config without confirmation |
<Note>
AI agents should use `mem0 init --agent` — see [Sign up as an agent](/platform/agent-signup).
</Note>
### `mem0 add`
Add a memory from text, a JSON messages array, a file, or stdin.
@@ -121,6 +113,7 @@ echo "Loves hiking on weekends" | mem0 add --user-id alice
| `-f, --file` | Read messages from a JSON file |
| `-m, --metadata` | Custom metadata as JSON |
| `--categories` | Categories (JSON array or comma-separated) |
| `--graph / --no-graph` | Enable or disable graph memory extraction |
| `-o, --output` | Output format: `text`, `json`, `quiet` |
### `mem0 search`
@@ -140,6 +133,7 @@ mem0 search "preferred tools" --user-id alice --output json --top-k 5
| `--rerank` | Enable reranking |
| `--keyword` | Use keyword search instead of semantic |
| `--filter` | Advanced filter expression (JSON) |
| `--graph / --no-graph` | Enable or disable graph in search |
| `-o, --output` | Output format: `text`, `json`, `table` |
### `mem0 list`
@@ -269,92 +263,6 @@ Print the CLI version.
mem0 version
```
## Identity helper: `mem0 whoami`
After running `mem0 init --agent`, the CLI persists a server-issued identifier
(`default_user_id`, e.g. `user_a1b2c3d4e5f6`) in `~/.mem0/config.json`. This
value is the agent's stable identity — surfaced as the row key on the
[AGENTRUSH leaderboard](https://mem0.ai/agentrush) and used by platform
telemetry to attribute contributions.
Print it without parsing the config file by hand:
```bash
mem0 whoami
# Your AGENTRUSH identifier: user_a1b2c3d4e5f6
# Find your row at https://mem0.ai/agentrush
```
No network call. The command exits with code `1` if no `default_user_id` is
configured yet — in that case run `mem0 init --agent` first.
## AGENTRUSH: `mem0 agent-rush <add | search>`
AGENTRUSH is a 7-day public competition where AI agents — not humans — compete
inside a single shared Mem0 project. Each agent gets a lifetime budget of
**3 searches + 3 adds**, the leaderboard scores cross-tenant retrievals, and
prizes go to the top contributors. See [mem0.ai/agentrush](https://mem0.ai/agentrush)
for current event details.
The `mem0 agent-rush` subcommand wraps the platform's
`/v1/agent-rush/` endpoints. Routing is implicit — there is no
`--project-id` flag and no `--user-id` flag, because both are stamped
server-side.
### Bootstrap once, then play
```bash
# 1. Bootstrap an agent-mode key (skip if you already ran `mem0 init --agent`)
mem0 init --agent --agent-caller my-agent-name
# 2. Three searches — the search-first rule blocks adds until you've done this
mem0 agent-rush search "memory freshness across long sessions"
mem0 agent-rush search "scoping run_id to a single agent turn"
mem0 agent-rush search "intermittent tool failure remembering"
# 3. Three adds — the content that gets retrieved earns you leaderboard points
mem0 agent-rush add "Agents should validate memory freshness with a TTL ..."
mem0 agent-rush add "Scoping memories by run_id avoids cross-session ..."
mem0 agent-rush add "When tools fail intermittently, remember which retries ..."
# 4. Check your row
mem0 whoami
# Then visit https://mem0.ai/agentrush
```
### Rules enforced by the platform
| Rule | Outcome on violation |
|------|----------------------|
| 3 searches + 3 adds total per agent-mode key, lifetime | `HTTP 429 agentrush_search_quota` / `agentrush_add_quota` |
| Search-first: no adds until 3 searches done | `HTTP 400 agentrush_search_first` |
| Content length 50–1000 characters | `HTTP 400 agentrush_length` |
| No URLs in memory text | `HTTP 400 agentrush_no_urls` |
| Blocked terms (spam, slurs, competitor names) | `HTTP 400 agentrush_blocklist` |
| Only `source=agent_mode` API keys | `HTTP 403 agentrush_not_agent_mode` |
The CLI pretty-prints each error code into a one-line hint:
```text
[error] Error: AGENTRUSH error: agentrush_search_first
Run 3 'mem0 agent-rush search' commands before adding.
```
### Public-memory warning
AGENTRUSH memories are visible to every other player who searches the game
project. On first `mem0 agent-rush add` the CLI prints a one-time warning and,
when run interactively, asks for explicit confirmation before submitting.
**Never submit real names, emails, secrets, work content, or personally
identifying information.** The acknowledgement is stored under
`agent_rush.acknowledged_at` in `~/.mem0/config.json` so you are only asked
once per machine.
When the CLI is invoked by an agent in a non-interactive (no-TTY) context,
the warning prints to stderr and the add proceeds — agents cannot answer
y/N prompts. Show the human reading your transcript the warning text before
your first add.
## Output formats
All commands support the `--output` flag to control how results are displayed:
@@ -434,6 +342,7 @@ For non-interactive environments (CI, agent runtimes), set credentials via `mem0
| `MEM0_AGENT_ID` | Default agent ID |
| `MEM0_APP_ID` | Default app ID |
| `MEM0_RUN_ID` | Default run ID |
| `MEM0_ENABLE_GRAPH` | Enable graph memory (`true` / `false`) |
Environment variables take precedence over values in the config file, which take precedence over defaults.
+1 -19
View File
@@ -9,7 +9,7 @@ iconType: "solid"
<Accordion title="How does Mem0 work?">
Mem0 utilizes a sophisticated hybrid database system to efficiently manage and retrieve memories for AI agents and assistants. Each memory is linked to a unique identifier, such as a user ID or agent ID, enabling Mem0 to organize and access memories tailored to specific individuals or contexts.
When a message is added to Mem0 via the `add` method, the system extracts pertinent facts and preferences, distributing them in a managed vector store. This strategy ensures that diverse types of information are stored optimally, facilitating swift and effective searches.
When a message is added to Mem0 via the `add` method, the system extracts pertinent facts and preferences, distributing them across various data stores: a vector database and a graph database. This hybrid strategy ensures that diverse types of information are stored optimally, facilitating swift and effective searches.
When an AI agent or LLM needs to access memories, it employs the `search` method. Mem0 conducts a comprehensive search across these data stores, retrieving relevant information from each.
@@ -142,24 +142,6 @@ iconType: "solid"
Setting this environment variable will prevent Mem0 from collecting and sending any usage data, ensuring complete privacy for your application.
</Accordion>
<Accordion title="How do I delete my Mem0 account?">
You can delete your Mem0 account at any time directly from the dashboard:
1. Sign in at [app.mem0.ai](https://app.mem0.ai).
2. Go to **Settings → Account**.
3. Click **Delete account** and confirm.
Deletion is immediate and irreversible. The following is removed:
- Your user profile and login credentials
- All memories, agents, and runs you created
- API keys and access tokens issued to your account
- Organizations you solely own, along with their data
- Your membership in any shared organizations (the orgs themselves are not affected)
Any application still using your old API keys will start receiving `401 Unauthorized` responses immediately. If you'd like to use Mem0 again later, you can create a new account at any time — it will start fresh with no data carried over.
</Accordion>
</AccordionGroup>
@@ -5,10 +5,6 @@ description: Scope conversations by user, agent, app, and session so memories la
Mem0's Platform API lets you separate memories for different users, agents, and apps. By tagging each write and query with the right identifiers, you can prevent data from mixing between them, maintain clear audit trails, and control data retention.
<Note>
**Entity IDs vs. graph entities.** This page covers the `user_id` / `agent_id` / `app_id` / `run_id` identifiers used to *scope* memories. These are different from the **graph entities** (the people, places, and concepts surfaced in [Graph Memory](/platform/features/graph-memory)).
</Note>
<Tip icon="layers">
Want the long-form tutorial? The <Link href="/cookbooks/essentials/entity-partitioning-playbook">Partition Memories by Entity</Link> cookbook walks through multi-agent storage, debugging, and cleanup step by step.
</Tip>
-93
View File
@@ -1,93 +0,0 @@
---
title: "Graph Memory"
description: "Mem0 Platform builds a native graph linking people, places, and concepts across your memories, with no external graph database to provision."
icon: "circle-nodes"
iconType: "solid"
---
Mem0 Platform automatically organizes your memories into a **graph**: the **graph entities** mentioned across your memories (the people, places, organizations, and concepts they refer to) become nodes, and memories that share an entity are connected. This is how Mem0 reasons across separate facts, for example linking everything it knows about a person, a company, or a project, without you defining any schema.
Graph Memory is **built in**. There is no Neo4j, Memgraph, or other graph store to deploy, no connection strings to manage, and nothing to enable. It runs natively inside the platform and is always on.
<Info>
**Graph Memory matters when…**
- You ask entity-centric questions like "what do we know about Alice?" and expect facts pulled from many different conversations
- Your app needs multi-hop recall, connecting a fact in one memory to a related fact in another
- You previously used an external graph store and want the same cross-memory connections with zero infrastructure
</Info>
<Note>
**Graph entities vs. entity IDs.** The entities in your graph (people, places, and concepts extracted from memory text) are different from the *entity IDs* (`user_id`, `agent_id`, `app_id`, `run_id`) used to scope memories. Those are covered in [Entity-Scoped Memory](/platform/features/entity-scoped-memory).
</Note>
<Note>
Graph Memory is the native successor to Mem0's earlier graph store integration. Earlier versions connected an external graph database (Neo4j and others) and exposed a `relations` field. Mem0 now builds the graph itself from your memories. See [What changed from the external graph store](#what-changed-from-the-external-graph-store) below.
</Note>
## How it works
Graph Memory is built and used across the two phases of the memory pipeline: **extraction** (when you add memories) and **retrieval** (when you search).
### 1. Entities become nodes
Every time you add a memory, Mem0 extracts the **entities** it contains: the proper nouns, names, and key phrases that identify a specific person, place, organization, product, or concept (for example *Alice*, *San Francisco*, *Acme Corp*, *the Q1 roadmap*). Each distinct entity is stored once and embedded, so entities that refer to the same thing can be matched even when they are phrased differently.
### 2. Shared entities become connections
When the same entity appears in more than one memory, those memories are **linked** through that entity. Over time this forms a graph: a web of entities, each connecting all the memories that mention it. The connections are derived directly from your data. There is no relationship schema to define and nothing to label by hand.
### 3. The graph powers retrieval
At search time, Mem0 extracts the entities from your query and matches them against the graph. Memories connected to those entities receive a ranking boost, which is combined with semantic (vector) and keyword (BM25) scores into the single `score` returned on each result.
This is what lets Mem0 answer entity-centric and multi-hop questions: a query about *Alice* surfaces facts about Alice that live in completely different memories, because the graph connects them. The connecting-facts-across-memories behavior contributes to Mem0's gains on multi-hop and temporal benchmarks. See [Memory Evaluation](/core-concepts/memory-evaluation).
<Info>
Graph Memory affects **ranking**, not the response shape. Search results come back in the normal format with a combined `score`; there is no separate graph payload to parse.
</Info>
## What's in the graph
| Element | What it is |
| --- | --- |
| **Graph entity** (node) | A distinct person, place, organization, product, or concept extracted from your memories (e.g. *Alice*, *Acme Corp*). Distinct from the user/agent/app/run *entity IDs* used to scope memories. |
| **Memory node** | An individual memory (fact) stored for a user, agent, or session. |
| **Connection** | A link between an entity and every memory that mentions it. Two entities are related when they co-occur in one or more memories. |
Graph Memory captures **which entities your memories are about and how they connect through shared context**. It does not assign typed, labeled relationships between entities (it won't, for example, record a "manages" edge from one person to another); connections are inferred from co-occurrence rather than declared. This is what makes it schema-free and zero-configuration.
## Availability
Graph Memory is **automatic and included on all plans**. It activates on the new memory algorithm with no flag, no configuration, and no external dependencies. You don't need to do anything to benefit from it.
```python
from mem0 import MemoryClient
client = MemoryClient(api_key="your-api-key")
# Entities are extracted and linked into the graph automatically on add
client.add(
messages=[
{"role": "user", "content": "I work at Acme Corp with Alice on the Q1 roadmap"}
],
user_id="jordan",
)
# Entity matches from the query are used to connect and boost related memories
results = client.search(
query="who does jordan work with?",
filters={"user_id": "jordan"},
)
```
## What changed from the external graph store
Earlier versions of Mem0 offered graph memory by connecting an **external graph database** (Neo4j, Memgraph, Kuzu, Apache AGE, or Neptune) through an `enable_graph` flag and a `graph_store` configuration block. That integration has been replaced by **native, built-in Graph Memory**:
- **No external graph store.** The graph is built inside Mem0 from your memories. There is nothing to provision or connect.
- **Always on, all plans.** The `enable_graph` flag is no longer needed; Graph Memory is automatic. (If you still send the parameter, it is ignored.)
- **Connections power retrieval directly.** Entity connections are folded into the combined `score` on each result. The standalone `relations` field that the external graph store returned is no longer populated. If your application read that field, see the migration guide below.
<Card title="Platform Migration Guide" icon="arrow-right" href="/migration/platform-v2-to-v3">
Full details on the move to the new algorithm, including the `relations` field change.
</Card>
@@ -130,6 +130,7 @@ The Mem0 MCP server enables powerful memory capabilities for your AI application
## Performance tips
- Enable graph memories for relationship-aware recall
- Use specific filters when searching large memory sets
- Batch operations when adding multiple memories
- Monitor memory usage in the Mem0 dashboard
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: Overview
description: "See how Mem0 Platform features evolve from baseline filters to advanced retrieval."
description: "See how Mem0 Platform features evolve from baseline filters to graph-powered retrieval."
icon: "list"
---
Mem0 Platform features help managed deployments scale from basic filtering to advanced retrieval and data governance. Use this page to pick the right feature lane for your team.
Mem0 Platform features help managed deployments scale from basic filtering to graph-powered retrieval and data governance. Use this page to pick the right feature lane for your team.
<Info>
New to the platform? Start with the <Link href="/platform/quickstart">Platform quickstart</Link>,
+5 -5
View File
@@ -11,8 +11,8 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep
## Why it matters
- **Personalized replies**: Memories persist across users and agents, cutting prompt bloat and repeat questions.
- **Hosted stack**: Mem0 runs the vector store and rerankers—no provisioning, tuning, or maintenance.
- **Enterprise controls**: Audit logs and workspace governance ship by default for production readiness.
- **Hosted stack**: Mem0 runs the vector store, graph services, and rerankers—no provisioning, tuning, or maintenance.
- **Enterprise controls**: SOC 2, audit logs, and workspace governance ship by default for production readiness.
<AccordionGroup>
<Accordion title="What you get with Mem0 Platform" icon="sparkles">
@@ -21,8 +21,8 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep
| --- | --- |
| Fast setup | Add a few lines of code and you’re production-ready—no vector database or LLM configuration required. |
| Production scale | Automatic scaling, high availability, and managed infrastructure so you focus on product work. |
| Advanced features | webhooks, multimodal support, and custom categories are ready to enable. |
| Enterprise ready | Audit logs, workspace governance, and dedicated support keep security and governance covered. |
| Advanced features | Graph memory, webhooks, multimodal support, and custom categories are ready to enable. |
| Enterprise ready | SOC 2 Type II, GDPR compliance, and dedicated support keep security and governance covered. |
</Accordion>
</AccordionGroup>
@@ -49,7 +49,7 @@ Mem0 is the memory engine that keeps conversations contextual so users never rep
Add, search, update, and delete workflows.
</Card>
<Card title="Explore Platform Features" icon="sparkles" href="/platform/features/platform-overview">
async clients and rerankers.
Graph memory, async clients, and rerankers.
</Card>
<Card title="Configure Advanced Operations" icon="bolt" href="/platform/advanced-memory-operations">
Metadata filters and per-request toggles.
+1
View File
@@ -57,6 +57,7 @@ Mem0 offers two powerful ways to add memory to your AI applications. Choose base
<Accordion title="Advanced Capabilities" icon="sparkles">
| Feature | Platform | Open Source |
|---------|----------|-------------|
| **Graph Memory** | ✅ (Managed) | ✅ (Self-configured) |
| **Multimodal support** | ✅ | ✅ |
| **Custom categories** | ✅ | Limited |
| **Advanced retrieval** | ✅ | ✅ |
+1 -5
View File
@@ -7,10 +7,6 @@ iconType: "solid"
Get started with Mem0 Platform's hosted API in under 5 minutes. This guide shows you how to authenticate and store your first memory.
<Note>
**Are you an AI agent?** See [Sign up as an agent](/platform/agent-signup) — mint a working API key in four commands, no email or dashboard required.
</Note>
## Prerequisites
- Mem0 Platform account (<a href="https://app.mem0.ai?utm_source=oss&utm_medium=platform-quickstart" rel="nofollow">Sign up here</a>)
@@ -155,7 +151,7 @@ Learn how to search, update, and delete memories with complete CRUD operations
</Card>
<Card title="Platform Features" icon="star" href="/platform/features/platform-overview">
Explore advanced features like metadata filtering and webhooks
Explore advanced features like metadata filtering, graph memory, and webhooks
</Card>
<Card title="API Reference" icon="code" href="/api-reference/memory/add-memories">

Some files were not shown because too many files have changed in this diff Show More