Compare commits

..

31 Commits

Author SHA1 Message Date
kartik-mem0 271c7c23c5 fix(mem0-plugin): remove noisy session-state dumps, match openclaw pattern
- Remove all background REST API transcript dumps (on_pre_compact.py,
  capture_compact_summary.py, on_pre_commit.py calls) that were creating
  noisy session_state and commit_context memories automatically
- Rewrite pre-compaction prompt to extract individual durable facts
  (decisions, learnings, anti-patterns) instead of session summary blobs
- Agent now decides what to store, matching openclaw's triage pattern:
  "Most sessions produce zero memory operations. That is correct."
- Fix auto_import.py to search git repo root for CLAUDE.md/AGENTS.md
  (was only searching plugin cwd, missing files in parent directory)
- Fix health check session tracker to check stats file directly instead
  of depending on CLAUDE_PLUGIN_ROOT env var
- Fix session-end report to print in SessionEnd hook (Stop hook output
  doesn't render on /exit)
- Update v2 API endpoint to v3 in git commit capture search
- Keep auto_import.py as only direct REST write path (project profiles,
  idempotent, hash-gated)
2026-05-22 16:20:31 +05:30
kartik-mem0 c2290299cf docs: add session stats file check and explanation to mem0-health skill 2026-05-22 15:33:59 +05:30
kartik-mem0 1b3a57e8ec refactor: update API endpoint to v3 in git commit capture script 2026-05-22 15:28:50 +05:30
kartik-mem0 245a70d90f refactor: update mem0-plugin scripts to use tool_output instead of tool_result 2026-05-22 14:53:56 +05:30
kartik-mem0 71a6696c87 refactor(mem0-plugin): improve hook scripts, config parsing, and skill definitions
Update git commit capture with better error handling, enhance user prompt hook,
extend config parser capabilities, and refine skill docs for dream, health,
mcp, pin, and stats skills.
2026-05-22 14:23:06 +05:30
kartik-mem0 6ab6ed58a8 refactor: update session start script and mem0-tour skill to display full memory content and use 2026-05-22 13:54:04 +05:30
kartik-mem0 1853543ceb Merge remote-tracking branch 'origin/main' into feat/mem0-plugin 2026-05-22 13:35:12 +05:30
kartik-mem0 93bb3b69c4 feat(mem0-plugin): add PostToolUseFailure, PostCompact, SessionEnd, SubagentStop hooks
Close 4 lifecycle coverage gaps:
- PostToolUseFailure: catch failed mem0 MCP calls, classify errors, inject retry guidance
- PostCompact: inject parallel search commands for context recovery after compaction
- SessionEnd: last-chance transcript capture with dedup against Stop hook
- SubagentStop: remind parent agent to persist subagent learnings

Also patch on_stop.sh to write capture marker for SessionEnd dedup.
2026-05-22 01:09:22 +05:30
kartik-mem0 97a3a2cf8d feat(mem0-plugin): complete all Tier 1-8 spec items, add scheduled dream and bash error detection
- Add /mem0:dream --schedule support via Claude Code /schedule command
  with local launchd/cron fallback for non-cloud users
- Add /mem0:digest --schedule and file output to ~/.mem0/weekly-digest.md
  with digest-history.log for trend tracking
- Add on_post_commit.sh PostToolUse hook: interactive prompt after git
  commit asking user to save change as memory with category suggestion
- Add on_bash_output.sh PostToolUse hook: detects stack traces and error
  patterns in bash command output, injects mem0 search rubric for prior
  occurrences (complements existing user prompt error detection)
- Fix session-end report: now shows per-category breakdown
  "wrote 3 memories (decision 2, anti_pattern 1)" matching spec
- Wire new hooks into all 3 platforms (Claude Code, Cursor, Codex)
- Add post_commit and bash_error telemetry events
- Add CTO demo testing guide with tier-by-tier manual test steps
2026-05-21 23:55:06 +05:30
kartik-mem0 b49626ab11 fix(mem0-plugin): wire pre-commit capture hook, add Setup hook, fix access counters
- Add PreToolUse(Bash) hook: detects `git commit` commands, fires
  on_pre_commit.py in background to capture staged changes as memory
- Add Setup(init|maintenance) hook: installs mem0ai SDK on first plugin
  install via ensure_deps.sh (120s timeout for slow networks)
- Add on_git_commit_capture.sh wrapper: reads tool input JSON, matches
  git commit/merge/rebase, runs capture script fire-and-forget
- Fix #24: add metadata.last_accessed ISO timestamp to access counter
  instructions in mem0-mcp/SKILL.md alongside existing access_count
2026-05-21 23:02:32 +05:30
kartik-mem0 eb1cdabe61 fix(mem0-plugin): remove userConfig from plugin.json, add auto-deps install
- Remove userConfig from .claude-plugin/plugin.json — OAuth flow handles
  auth via mcp.mem0.ai, userConfig prompt was redundant and confusing
- Add ensure_deps.sh to install mem0ai SDK into persistent plugin venv
- Add requirements.txt (mem0ai) for dependency tracking
- Wire SessionStart hook to auto-install deps on first run
- Update setup_coding_categories.py to find venv site-packages
- Update onboarding SKILL.md with venv-aware install steps
2026-05-21 22:52:27 +05:30
kartik-mem0 141782a230 fix(mem0-plugin): use env var in .mcp.json, fix onboarding MCP check
- .mcp.json: use ${MEM0_API_KEY} instead of ${user_config.MEM0_API_KEY}
  so MCP connects for --plugin-dir users with the key in their shell
- mem0-onboard: check MCP tools availability first, stop early with
  clear instructions if MCP server not connected
2026-05-21 21:29:19 +05:30
kartik-mem0 d5b15cebb7 feat(mem0-plugin): add PostHog telemetry across all hooks
Wire fire-and-forget PostHog telemetry into every lifecycle hook
(session_start, stop, pre_compact, task_completed, user_prompt,
post_tool_use) matching the same project key, endpoint, and payload
structure used by the Python SDK, CLI, and OpenClaw.

- 10% sampling on ALL events to keep PostHog costs predictable
- Anonymous distinct_id: MD5(api_key) or SHA-256(username)
- Opt-out via MEM0_TELEMETRY=false
- Platform detection: Claude Code / Cursor / Codex
- Never sends user content, API keys, or raw identifiers
- 16 new tests (110 total passing)
2026-05-21 21:08:21 +05:30
kartik-mem0 c5bb11b8b1 fix(mem0-plugin): graceful degradation without API key, stdin support
- SessionStart shows "Mem0 Inactive" banner with identity info when no
  API key set, instead of silently exiting with zero output
- on_user_prompt.sh fires error/file-path detection even without API key
  (local pattern matching, no API needed). Search rubric still gated.
- parse_export_file.py supports '-' argument for stdin piping
2026-05-21 19:13:13 +05:30
kartik-mem0 1daa7ece66 fix(mem0-plugin): fix 3 critical + 5 important issues from review
Critical fixes:
- C1: Pin/dream update_memory now reads content first via get_memory
  before updating, preventing metadata-only calls that wipe content
- C2: SessionStart memory count uses GET /v3/memories/?page_size=1 for
  real count from pagination envelope instead of search limit=100
- C3: on_task_completed.sh uses ${MEM0_PROJECT_ID:-unknown} to avoid
  crash when identity resolution fails under set -u

Important fixes:
- I1: session_stats.py tracks recent_ids (memory IDs + timestamps) for
  /mem0:forget undo support. Capped at 50 entries.
- I2: /mem0:health --deep mode adds memory quality analysis: duplicate
  detection, stale entry scan, contradiction flags, orphan tagging
- I3: /mem0:stats ASCII histogram for category distribution with bar
  chart, sorted by count descending
- I4: mem0-mcp skill documents access counter pattern: get_memory then
  update_memory to track which memories are actually used
- I5: on_pre_commit.py reads COMMIT_EDITMSG first (current commit),
  falls back to HEAD only if EDITMSG unavailable

Tests: 91 -> 94 (3 new for recent_ids tracking)
2026-05-21 18:46:08 +05:30
kartik-mem0 70f2f60727 chore(mem0-plugin): remove TESTING.md from tracking
Manual testing guide will be local-only, not committed to repo.
2026-05-21 18:42:02 +05:30
kartik-mem0 35da92ba88 docs(mem0-plugin): comprehensive TESTING.md covering all Tiers 1-8
Rewrote TESTING.md with behavioral tests for every tier item:
- v3 endpoint verification for all 5 write scripts + search
- app_id scoping and branch tagging checks
- Skill content validation (confidence, citations, recency, infer=False)
- Robustness checks (loop guard, set flags, fallback stubs)
- 28-item checklist covering all 34 roadmap items
- Fixed stale comment in on_stop.sh
2026-05-21 18:40:48 +05:30
kartik-mem0 4b94902446 fix(mem0-plugin): review fixes — loop guard, v3 response format, robustness
- on_stop_cursor.sh: add loop_count guard to prevent infinite re-entry
- on_stop.sh: drop set -e so stats failure doesn't kill the reminder
- _identity.py: fix fallback stub signatures to match production (accept cwd arg)
- on_pre_compact.py: add missing infer=False on session_state writes
- on_session_start.sh: handle v3 search response format (dict with results key)
- Align all plugin versions to 0.2.1 (Claude Code, Codex, Cursor)
2026-05-21 18:27:47 +05:30
kartik-mem0 470cef6ba6 fix(mem0-plugin): upgrade REST endpoints to v3, fix dream scheduling docs
- All add_memory REST calls now use /v3/memories/add/ (was /v1/memories/)
- Session start search uses /v3/memories/search/ (was /v2/memories/search/)
- Dream skill: removed reference to nonexistent /schedule skill
  (Claude Code has no native scheduling — recommend external cron instead)
2026-05-21 18:14:19 +05:30
kartik-mem0 930f6ec51d feat(mem0-plugin): power-user skills + expanded mem0.md config (Tier 8)
Power-user tier:
- /mem0:remember: quick-add with auto-classification, infer=False, confidence=1.0
- /mem0:forget: search-confirm-delete flow with numbered list
- /mem0:pin: mark memories as pinned via metadata update
- /mem0:peek: compact one-liner search results
- parse_mem0_config.py: expanded to parse ## Search, ## Categories, ## Identity
- on_session_start.sh: inject mem0.md project config into session context
2026-05-21 18:14:09 +05:30
kartik-mem0 cd66050748 feat(mem0-plugin): smart retrieval, citations, pre-commit capture (Tier 7)
Smart retrieval tier:
- on_user_prompt.sh: stack-trace detection (auto-searches anti_patterns on errors)
- on_user_prompt.sh: file-aware retrieval (extracts file paths, suggests scoped search)
- on_user_prompt.sh: recency boost guidance for state-related queries
- mem0-mcp/SKILL.md: inline citation format [mem0:<8char_id>]
- on_pre_commit.py: captures staged diff as commit_context memory via REST API
2026-05-21 18:13:59 +05:30
kartik-mem0 81211be473 feat(mem0-plugin): add /mem0:stats, /mem0:health, /mem0:digest skills (Tier 6)
Observability tier:
- /mem0:stats: session + lifetime memory dashboard with category breakdown
- /mem0:health: 5-check diagnostic (API key, identity, MCP, write/read, tracker)
- /mem0:digest: weekly memory activity summary with time-scoped searches
- session_stats.py: add `peek` command (JSON without clearing), per-category counters
2026-05-21 18:13:44 +05:30
kartik-mem0 82ab253f2c fix(mem0-plugin): sanitize marker path, add pre-compact REST backup, fix cross-tool gaps
- Sanitize project_id in onboard marker path (tr '/:' '--') to handle
  slashes from env var overrides
- Fire on_pre_compact.py REST backup from PreCompact hook (was only
  called from Stop hooks — crash before Stop = data loss)
- Source _identity.sh in on_stop_codex.sh and on_stop_cursor.sh so
  MEM0_PROJECT_ID + API key fallback are available
- Note dream --schedule is Claude Code-only (Codex/Cursor lack schedule)
2026-05-21 17:43:40 +05:30
kartik-mem0 63641f5573 feat(mem0-plugin): add export/import skills + competing tool importers
Tier 3 implementation:
- #10: Unified project_id resolver already complete (shared scripts/)
- #11: /mem0:export dumps all project memories as YAML-frontmatter
  markdown; /mem0:import restores from same format. Round-trip capable.
  parse_export_file.py handles parsing (stdlib-only).
- #12: import_competing_tools.py imports from .cursorrules, copilot
  instructions, cline memory-bank, continue.dev rules. Splits by
  section headers, POSTs with app_id + infer=False.
2026-05-21 17:43:30 +05:30
kartik-mem0 b79be63e30 feat(mem0-plugin): add /mem0:dream consolidation + retention policies
Tier 4 implementation:
- #13+15: /mem0:dream skill — fetches all memories, finds near-dupes,
  proposes merges, flags contradictions, prunes stale entries per
  retention policy, outputs terminal diff for user approval
- #14: --schedule weekly registers cron via Claude Code schedule skill
  (Claude Code only, noted in docs)
- #16: parse_mem0_config.py parses ## Retention section from mem0.md
  (e.g. session_state: 90d, architecture_decisions: forever)
2026-05-21 17:43:14 +05:30
kartik-mem0 6ed5fcf76e feat(mem0-plugin): expand categories to 17, add recall rubric + confidence + files tagging
Tier 5 implementation:
- #17: Expand coding categories from 7 to 17 (dependency_decisions,
  performance_findings, security_constraints, testing_patterns, data_model,
  api_contracts, deployment_runbook, team_norms, domain_glossary,
  experiment_results)
- #18: Category-recall rubric table in mem0-mcp/SKILL.md mapping user
  intent to 2-3 categories for parallel search fan-out
- #19: metadata.confidence scoring rules (1.0/0.8/0.5/0.3 scale)
- #20: metadata.files array tagging for affected file paths
2026-05-21 17:43:01 +05:30
kartik-mem0 f6c3432e19 fix(mem0-plugin): fix userConfig schema and restore ${user_config.*} in .mcp.json
userConfig was missing required `type` and `title` fields per Claude Code
plugin docs — value was never collected, so ${user_config.MEM0_API_KEY}
could not resolve. Added both fields. Restored .mcp.json to use
${user_config.MEM0_API_KEY} for the MCP server Authorization header.

This completes the fix for #4876: plugin now prompts for API key at
install, stores in keychain, and MCP server reads it via user_config
interpolation — no shell env var needed.
2026-05-21 17:15:09 +05:30
kartik-mem0 15916a78e0 fix(mem0-plugin): revert .mcp.json to ${MEM0_API_KEY} env var
${user_config.*} interpolation not supported in HTTP-type MCP server
headers — only works for subprocess-based servers. Revert to shell
env var reference. The userConfig + resolve_api_key() fallback chain
still fixes hook scripts for issue #4876.
2026-05-21 17:13:11 +05:30
kartik-mem0 ff2f6c281a fix(mem0-plugin): resolve API key from userConfig, fix #4876
Root cause: .mcp.json required ${MEM0_API_KEY} shell env var which
OAuth flow never populates — MCP server never started, only auth
stubs were exposed.

Fix: switch .mcp.json to ${user_config.MEM0_API_KEY} so Claude Code
reads the key from plugin userConfig (system keychain). Add
resolve_api_key() fallback chain (MEM0_API_KEY -> CLAUDE_PLUGIN_OPTION_MEM0_API_KEY)
to all hook scripts. Update onboard skill and setup_coding_categories.py
to handle keychain-only users. Add 3 tests for key resolution.
2026-05-21 17:10:17 +05:30
kartik-mem0 66600565ed fix(mem0-plugin): thread cwd to resolvers, add write-path tests, userConfig for API key
- on_pre_compact.py and capture_compact_summary.py now read cwd from
  hook stdin and pass it to resolve_project_id/resolve_branch (monorepo safe)
- 5 new tests verify all write functions use app_id top-level and never
  put project_id in metadata
- plugin.json declares userConfig.MEM0_API_KEY so Claude Code prompts
  for the key at install time (sensitive, stored in system keychain)
2026-05-21 16:50:11 +05:30
kartik-mem0 cf6db6ef88 fix(mem0-plugin): use app_id entity scoping, fix tour, add branch tagging
Tour was filtering on metadata.type which missed platform-categorized
memories. Rewritten to use get_memories (list all) + group by platform
categories field. All write hooks now use app_id as top-level entity
param instead of metadata.project_id. Branch stamped on every write.
2026-05-21 16:38:48 +05:30
1339 changed files with 61603 additions and 53112 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.12"
"version": "0.1.3"
}
]
}
-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.12"
"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."
+1 -3
View File
@@ -1,11 +1,9 @@
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:
pull_request:
jobs:
changelog_check:
+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.
+43 -130
View File
@@ -1,157 +1,72 @@
# Contributing to Mem0
# Contributing to mem0
First off, thank you for taking the time to contribute! 🎉 Mem0 is a
community-driven project and we welcome contributions of all kinds — bug fixes,
new features, documentation, examples, and integrations.
Let us make contribution easy, collaborative and fun.
Mem0 is a polyglot monorepo, and this guide covers contributing to both the
**Python SDK** and the **TypeScript SDK** (and the rest of the repository).
## Submit your Contribution through PR
## Before You Start
To make a contribution, follow these steps:
### 1. Open an Issue First
1. Fork and clone this repository
2. Do the changes on your fork with dedicated feature branch `feature/f1`
3. If you modified the code (new feature or bug-fix), please add tests for it
4. Include proper documentation / docstring and examples to run the feature
5. Ensure that all tests pass
6. Submit a pull request
**Always open an issue before opening a pull request.** This lets us discuss the
change, avoid duplicate effort, and agree on the approach before you invest time
in code.
For more details about pull requests, please read [GitHub's guides](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
- Search [existing issues](https://github.com/mem0ai/mem0/issues) first to see if
your bug or idea already exists.
- If it doesn't, open a
[bug report](https://github.com/mem0ai/mem0/issues/new?template=bug_report.yml) or
[feature request](https://github.com/mem0ai/mem0/issues/new?template=feature_request.yml).
- For anything beyond a trivial fix, wait for a maintainer to confirm the approach
before starting significant work.
Every pull request must link to an issue using `Closes #<issue-number>`.
### 📦 Development Environment
### 2. Sign the Contributor License Agreement (CLA)
**We cannot accept or merge any pull request until you have signed our Contributor
License Agreement (CLA).**
When you open your first PR, the CLA bot will automatically comment with a link to
sign. Signing takes less than a minute and only needs to be done once. Pull
requests from contributors who have not signed the CLA will be blocked from
merging.
## Repository Layout
The two most common contribution targets are the SDKs:
| Package | Path | Language | Package manager |
| --------------------- | ---------- | ------------ | --------------- |
| Python SDK (`mem0ai`) | `mem0/` | Python 3.9+ | `hatch` |
| TypeScript SDK (`mem0ai`) | `mem0-ts/` | TypeScript | `pnpm` |
Other packages include the CLIs (`cli/python/`, `cli/node/`), integrations
(`integrations/`), the self-hosted `server/`, `openmemory/`, and the docs site
(`docs/`). See [AGENTS.md](./AGENTS.md) for a full map of the repository.
## Development Workflow
1. **Fork** the repository and **clone** your fork.
2. Create a **feature branch** from `main` (e.g. `feature/my-new-feature` or
`fix/issue-1234`).
3. Make your changes — add **tests**, **documentation**, and **examples** as
appropriate.
4. Run **linting and tests** for every package you touched (see below).
5. Commit using [Conventional Commits](https://www.conventionalcommits.org/)
(e.g. `feat:`, `fix:`, `docs:`, `refactor:`, `test:`).
6. Push and open a **pull request** against `main`, linking the issue with
`Closes #<number>` and filling out the
[PR template](./.github/PULL_REQUEST_TEMPLATE.md).
### Contributing to the Python SDK (`mem0/`)
We use [`hatch`](https://hatch.pypa.io/latest/install/) to manage environments.
**Do not use `pip` or `conda` for dependency management.**
We use `hatch` for managing development environments. To set up:
```bash
# Activate a dev environment (3.9 / 3.10 / 3.11 / 3.12)
hatch shell dev_py_3_11
# Activate environment for specific Python version:
hatch shell dev_py_3_9 # Python 3.9
hatch shell dev_py_3_10 # Python 3.10
hatch shell dev_py_3_11 # Python 3.11
hatch shell dev_py_3_12 # Python 3.12
# Install pre-commit hooks (runs ruff + isort on commit)
pre-commit install
# Lint, format, and sort imports
make lint
make format
make sort
# Run the test suite (run `make install_all` first if deps are missing)
# The environment will automatically install all dev dependencies
# Run tests within the activated shell:
make test
```
- **Linter / formatter:** Ruff (line length **120**)
- **Import sorting:** isort (`profile = "black"`)
- **Tests:** pytest (in `tests/`)
### 📌 Pre-commit
See the full [Development guide](https://docs.mem0.ai/contributing/development) for
environment details.
### Contributing to the TypeScript SDK (`mem0-ts/`)
We use [`pnpm`](https://pnpm.io/) (v10+) for all TypeScript packages. **Do not use
`npm` or `yarn`.**
To ensure our standards, make sure to install pre-commit before starting to contribute.
```bash
cd mem0-ts
pnpm install
pnpm run build # tsup (CJS + ESM)
pnpm run test # jest (all tests)
pnpm run test:unit # unit tests with coverage
pre-commit install
```
- **Build:** tsup
- **Formatter:** Prettier
- **Tests:** jest
- Always run type checking after changes: `pnpm run typecheck` (or `tsc --noEmit`).
- Use ES module `import` syntax — never `require()`.
### 🧪 Testing
## Good Contribution Practices
We use `pytest` to test our code across multiple Python versions. You can run tests using:
- **Keep PRs small and focused.** One logical change per PR is easier to review and
merge.
- **Follow existing patterns.** Match the style, structure, and conventions of the
code around you. Don't introduce new frameworks or abstractions without
discussion.
- **Write tests** that would fail without your change — regression tests for bugs,
coverage for new features.
- **Update documentation** in `docs/` for any user-facing change. New `.mdx` pages
must be added to `docs/llms.txt` (run
`python scripts/check-llms-txt-coverage.py --write` to scaffold entries).
- **Add examples** when introducing new user-facing behavior.
- **Run linters and tests locally** before pushing — CI re-runs them on every PR
via the CI Gate.
- **Never commit secrets** — no `.env` files, API keys, or credentials.
- **Don't add core dependencies lightly.** New Python dependencies belong in an
optional group in `pyproject.toml`, not the core `dependencies` list.
- **Be responsive** to review feedback and keep your branch up to date with `main`.
```bash
# Run tests with default Python version
make test
## Pull Request Checklist
# Test specific Python versions:
make test-py-3.9 # Python 3.9 environment
make test-py-3.10 # Python 3.10 environment
make test-py-3.11 # Python 3.11 environment
make test-py-3.12 # Python 3.12 environment
Before requesting review, make sure:
# When using hatch shells, run tests with:
make test # After activating a shell with hatch shell test_XX
```
- [ ] An issue exists and is linked with `Closes #<number>`
- [ ] You have signed the CLA
- [ ] Your code follows the project's style guidelines (lint passes)
- [ ] You performed a self-review of your changes
- [ ] Tests are added/updated and pass locally
- [ ] Documentation is updated if needed
Make sure that all tests pass across all supported Python versions before submitting a pull request.
## Reporting Security Issues
We look forward to your pull requests and can't wait to see your contributions!
**Do not report security vulnerabilities through public issues or pull requests.**
Please follow our [Security Policy](./SECURITY.md) to report them privately.
### 🚀 Releasing
## Releasing
All packages are published automatically via GitHub Actions when a GitHub Release is created with the correct tag prefix.
All packages are published automatically via GitHub Actions when a GitHub Release
is created with the correct tag prefix.
### Tag Prefixes
#### Tag Prefixes
| Package | Registry | Tag Prefix | Example |
|---------|----------|------------|---------|
@@ -162,17 +77,15 @@ is created with the correct tag prefix.
| `@mem0/vercel-ai-provider` | npm | `vercel-ai-v*` | `vercel-ai-v2.0.6` |
| `@mem0/openclaw-mem0` | npm | `openclaw-v*` | `openclaw-v1.0.1` |
### How to Release
#### How to Release
1. Bump the version in `pyproject.toml` (Python) or `package.json` (Node)
2. Create a [GitHub Release](https://github.com/mem0ai/mem0/releases/new) with the matching tag prefix
3. The correct workflow will trigger automatically — verify in the [Actions tab](https://github.com/mem0ai/mem0/actions)
### Publishing Details
#### Publishing Details
- **PyPI packages** use OIDC trusted publishing via `pypa/gh-action-pypi-publish`
- **npm packages** use OIDC trusted publishing via npm CLI (>= 11.5.1) — no tokens or secrets required
- All workflows require `permissions: id-token: write` for OIDC authentication
- First publish of a new npm package must be done manually; OIDC works for subsequent versions
We look forward to your pull requests and can't wait to see your contributions!
+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!")
```
+1 -2
View File
@@ -186,10 +186,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
-48
View File
@@ -1,48 +0,0 @@
# Security Policy
We take the security of Mem0 and our community seriously. Thank you for helping
keep Mem0 and its users safe by disclosing vulnerabilities responsibly.
## Reporting a Vulnerability
Please **do not** report security vulnerabilities through public GitHub issues,
pull requests, or discussions.
If you believe you have found a security vulnerability in Mem0, please report it
privately through one of the following channels:
1. **GitHub Private Vulnerability Reporting** — open a
[private security advisory](https://github.com/mem0ai/mem0/security/advisories/new)
directly on this repository.
2. **Email** the maintainers at **support@mem0.ai** with the subject line:
`SECURITY: Mem0 vulnerability report`
To help us triage and resolve the issue quickly, please include as much of the
following as you can:
- Affected component or package (e.g. Python SDK, TypeScript SDK, server, OpenMemory)
- Affected version, tag, or commit
- Clear, step-by-step reproduction instructions
- The security impact and a proof of concept, if available
- Any suggested fix or mitigation
## Response Process
- We will acknowledge receipt of your report within **72 hours**.
- We will work with you privately to confirm the issue and assess its impact.
- Once a fix or mitigation is ready, we will coordinate a disclosure timeline
with you and credit you for the discovery, unless you prefer to remain anonymous.
## Public Disclosure
Please avoid sharing technical details of the vulnerability publicly until the
maintainers have reviewed the issue and a fix or mitigation has been released. We
are committed to resolving valid reports promptly and keeping you informed
throughout the process.
## Supported Versions
We release security fixes against the latest published version of each package.
Whenever possible, please reproduce the issue on the most recent release before
reporting.
+36
View File
@@ -0,0 +1,36 @@
# 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.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.10",
"version": "0.2.7",
"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"
+4 -6
View File
@@ -316,18 +316,16 @@ export class PlatformBackend implements Backend {
if (entities.length === 0) {
throw new Error("At least one entity ID is required for deleteEntities.");
}
// Delete each provided entity via the v2 path-based endpoint. Key each
// response by entity type so a multi-entity delete (e.g. --user-id and
// --agent-id together) doesn't discard everything but the last result.
const results: Record<string, unknown> = {};
// Delete each provided entity via the v2 path-based endpoint
let result: Record<string, unknown> = {};
for (const [entityType, entityId] of entities) {
results[entityType] = (await this._request(
result = (await this._request(
"DELETE",
`/v2/entities/${entityType}/${entityId}/`,
{ params: { source: "CLI" } },
)) as Record<string, unknown>;
}
return results;
return result;
}
async ping(): Promise<Record<string, unknown>> {
+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,
});
+5 -5
View File
@@ -145,11 +145,11 @@ export function captureEvent(
anonDistinctIdToAlias: anonIdToAlias,
};
const child = spawn(process.execPath, [SENDER_SCRIPT], {
detached: true,
stdio: ["pipe", "ignore", "ignore"],
});
child.stdin?.end(JSON.stringify(context));
const child = spawn(
process.execPath,
[SENDER_SCRIPT, JSON.stringify(context)],
{ detached: true, stdio: "ignore" },
);
child.unref();
} catch {
/* silently swallow */
+2 -28
View File
@@ -1,8 +1,7 @@
/**
* Standalone telemetry sender — runs as a detached child process.
*
* Usage: node telemetry-sender.cjs (JSON context is read from stdin; a single
* argv argument is still accepted as a legacy fallback)
* Usage: node telemetry-sender.cjs '<json context>'
*
* This script is spawned by telemetry.captureEvent() and runs independently
* of the parent CLI process. It:
@@ -20,31 +19,6 @@
const https = require("https");
const fs = require("fs");
function loadContext() {
return new Promise((resolve, reject) => {
if (process.argv[2]) {
try {
resolve(JSON.parse(process.argv[2]));
} catch (err) {
reject(err);
}
return;
}
let data = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => (data += chunk));
process.stdin.on("end", () => {
try {
resolve(JSON.parse(data));
} catch (err) {
reject(err);
}
});
process.stdin.on("error", reject);
});
}
function httpsRequest(url, method, headers, body) {
return new Promise((resolve, reject) => {
const u = new URL(url);
@@ -134,7 +108,7 @@ async function sendIdentifyEvent(ctx, payload, anonId) {
}
async function main() {
const ctx = await loadContext();
const ctx = JSON.parse(process.argv[2]);
const payload = ctx.payload;
if (ctx.needsEmail && ctx.mem0ApiKey) {
+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());
-52
View File
@@ -1,52 +0,0 @@
/**
* Tests for the Platform backend (mem0 Platform API client).
*/
import { describe, it, expect, vi } from "vitest";
import { PlatformBackend } from "../src/backend/platform.js";
import { createDefaultConfig } from "../src/config.js";
function makeBackend(): PlatformBackend {
// apiKey/baseUrl only build request headers; every test spies on _request,
// so no real network calls are made.
return new PlatformBackend(createDefaultConfig().platform);
}
describe("deleteEntities", () => {
it("returns all results keyed by entity type for a multi-entity delete", async () => {
const backend = makeBackend();
const responses: Record<string, unknown> = {
"/v2/entities/user/alice/": { message: "user deleted" },
"/v2/entities/agent/bob/": { message: "agent deleted" },
};
const spy = vi
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
.spyOn(backend as any, "_request")
.mockImplementation(async (_method: string, path: string) => responses[path]);
const result = await backend.deleteEntities({ userId: "alice", agentId: "bob" });
// Regression: previously only the last entity's response survived.
expect(result).toEqual({
user: { message: "user deleted" },
agent: { message: "agent deleted" },
});
expect(spy).toHaveBeenCalledTimes(2);
});
it("keys a single-entity delete by its type", async () => {
const backend = makeBackend();
// biome-ignore lint/suspicious/noExplicitAny: spying on a private method
vi.spyOn(backend as any, "_request").mockResolvedValue({ message: "user deleted" });
const result = await backend.deleteEntities({ userId: "alice" });
expect(result).toEqual({ user: { message: "user deleted" } });
});
it("throws when no entity id is provided", async () => {
const backend = makeBackend();
await expect(backend.deleteEntities({})).rejects.toThrow(
"At least one entity ID is required",
);
});
});
-59
View File
@@ -1,59 +0,0 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
const mockLoadConfig = vi.fn();
const mockSaveConfig = vi.fn();
const mockSpawn = vi.fn();
vi.mock("../src/config.js", () => ({
CONFIG_FILE: "/tmp/mem0-config.json",
loadConfig: mockLoadConfig,
saveConfig: mockSaveConfig,
}));
vi.mock("node:child_process", () => ({
spawn: mockSpawn,
}));
describe("captureEvent", () => {
beforeEach(() => {
vi.resetModules();
mockLoadConfig.mockReset();
mockSaveConfig.mockReset();
mockSpawn.mockReset();
delete process.env.MEM0_TELEMETRY;
});
it("pipes the telemetry context through stdin instead of argv", async () => {
mockLoadConfig.mockReturnValue({
platform: {
apiKey: "m0-node-secret",
baseUrl: "https://api.mem0.ai",
userEmail: "",
},
telemetry: {
anonymousId: "cli-anon-node",
},
});
const stdin = { end: vi.fn() };
const child = { stdin, unref: vi.fn() };
mockSpawn.mockReturnValue(child);
const { captureEvent } = await import("../src/telemetry.js");
captureEvent("node_test_event", { case: "stdin-secret" });
expect(mockSpawn).toHaveBeenCalledTimes(1);
const [execPath, args, options] = mockSpawn.mock.calls[0];
expect(execPath).toBe(process.execPath);
expect(args).toHaveLength(1);
expect(String(args[0])).toContain("telemetry-sender.cjs");
expect(JSON.stringify(args)).not.toContain("m0-node-secret");
expect(options).toMatchObject({ detached: true, stdio: ["pipe", "ignore", "ignore"] });
expect(stdin.end).toHaveBeenCalledTimes(1);
const payload = JSON.parse(stdin.end.mock.calls[0][0]);
expect(payload.mem0ApiKey).toBe("m0-node-secret");
expect(payload.payload.event).toBe("node_test_event");
expect(child.unref).toHaveBeenCalledTimes(1);
});
});
-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
@@ -0,0 +1,36 @@
# 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.9"
version = "0.2.7"
description = "The official CLI for mem0 — the memory layer for AI agents"
readme = "README.md"
license = "Apache-2.0"
+1 -1
View File
@@ -1,3 +1,3 @@
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
__version__ = "0.2.9"
__version__ = "0.2.4"
+4 -6
View File
@@ -296,15 +296,13 @@ class PlatformBackend(Backend):
entities = {t: v for t, v in type_map.items() if v}
if not entities:
raise ValueError("At least one entity ID is required for delete_entities.")
# Delete each provided entity via the v2 path-based endpoint. Key each
# response by entity type so a multi-entity delete (e.g. --user-id and
# --agent-id together) doesn't discard everything but the last result.
results: dict = {}
# Delete each provided entity via the v2 path-based endpoint
result: dict = {}
for entity_type, entity_id in entities.items():
results[entity_type] = self._request(
result = self._request(
"DELETE", f"/v2/entities/{entity_type}/{entity_id}/", params={"source": "CLI"}
)
return results
return result
def ping(self, timeout: float | None = None) -> dict:
"""Call the ping endpoint and return the raw response.
+1 -4
View File
@@ -235,10 +235,7 @@ def set_nested_value(config: Mem0Config, dotted_key: str, value: str) -> bool:
if isinstance(current, bool):
value = value.lower() in ("true", "1", "yes") # type: ignore[assignment]
elif isinstance(current, int):
try:
value = int(value) # type: ignore[assignment]
except ValueError:
return False
value = int(value) # type: ignore[assignment]
setattr(obj, final_key, value)
return True
+6 -6
View File
@@ -20,8 +20,8 @@ def format_memories_text(console: Console, memories: list[dict], title: str = "m
console.print(f"\n[{BRAND_COLOR}]Found {count} {title}:[/]\n")
for i, mem in enumerate(memories, 1):
memory_text = mem.get("memory") or mem.get("text") or ""
mem_id = (mem.get("id") or "")[:8]
memory_text = mem.get("memory", mem.get("text", ""))
mem_id = mem.get("id", "")[:8]
score = mem.get("score")
created = _format_date(mem.get("created_at"))
category = mem.get("categories", [None])
@@ -67,8 +67,8 @@ def format_memories_table(
table.add_column("Created", max_width=12)
for mem in memories:
mem_id = mem.get("id") or ""
memory_text = mem.get("memory") or mem.get("text") or ""
mem_id = mem.get("id", "")
memory_text = mem.get("memory", mem.get("text", ""))
if len(memory_text) > 60:
memory_text = memory_text[:57] + "..."
categories = mem.get("categories", [])
@@ -104,8 +104,8 @@ def format_single_memory(console: Console, mem: dict, output: str = "text") -> N
format_json(console, mem)
return
memory_text = mem.get("memory") or mem.get("text") or ""
mem_id = mem.get("id") or ""
memory_text = mem.get("memory", mem.get("text", ""))
mem_id = mem.get("id", "")
lines = []
lines.append(f" [white bold]{memory_text}[/]")
+2 -9
View File
@@ -137,19 +137,12 @@ def capture_event(
"anon_distinct_id_to_alias": anon_id_to_alias,
}
child = subprocess.Popen(
[sys.executable, "-m", "mem0_cli.telemetry_sender"],
stdin=subprocess.PIPE,
subprocess.Popen(
[sys.executable, "-m", "mem0_cli.telemetry_sender", json.dumps(context)],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True,
close_fds=True,
text=True,
)
if child.stdin:
with contextlib.suppress(Exception):
child.stdin.write(json.dumps(context))
with contextlib.suppress(Exception):
child.stdin.close()
except Exception:
pass
+2 -13
View File
@@ -1,7 +1,6 @@
"""Standalone telemetry sender — runs as a detached subprocess.
Usage: python -m mem0_cli.telemetry_sender (JSON context is read from stdin;
a single argv argument is still accepted as a legacy fallback)
Usage: python -m mem0_cli.telemetry_sender '<json context>'
This module is spawned by telemetry.capture_event() and runs independently
of the parent CLI process. It:
@@ -21,18 +20,8 @@ import sys
import urllib.request
def _load_context() -> dict:
"""Load telemetry context from stdin, falling back to argv for compatibility."""
raw = ""
if not sys.stdin.isatty():
raw = sys.stdin.read().strip()
if not raw and len(sys.argv) > 1:
raw = sys.argv[1]
return json.loads(raw)
def main() -> None:
ctx = _load_context()
ctx = json.loads(sys.argv[1])
payload = ctx["payload"]
if ctx.get("needs_email") and ctx.get("mem0_api_key"):
+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 -7
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()
@@ -139,11 +138,6 @@ class TestNestedAccess:
assert set_nested_value(config, "platform.api_key", "new-key")
assert config.platform.api_key == "new-key"
def test_set_int_value_rejects_invalid_input(self):
config = Mem0Config()
assert set_nested_value(config, "version", "abc") is False
assert config.version == 1
def test_set_nonexistent_key(self):
config = Mem0Config()
assert set_nested_value(config, "nonexistent.key", "val") is False
-23
View File
@@ -54,11 +54,6 @@ class TestTextFormat:
output = buf.getvalue()
assert "Found 0" in output
def test_format_memories_text_handles_null_fields(self):
console, buf = _make_console()
format_memories_text(console, [{"id": None, "memory": None, "created_at": None}])
assert "Found 1 memories" in buf.getvalue()
class TestTableFormat:
def test_format_memories_table(self):
@@ -75,13 +70,6 @@ class TestTableFormat:
# Should still render (empty table)
assert "ID" in output
def test_format_memories_table_handles_null_fields(self):
console, buf = _make_console()
format_memories_table(console, [{"id": None, "memory": None, "created_at": None}])
output = buf.getvalue()
assert "ID" in output
assert "Memory" in output
class TestSingleMemory:
def test_format_single_memory_text(self):
@@ -99,17 +87,6 @@ class TestSingleMemory:
output = buf.getvalue()
assert '"memory"' in output
def test_format_single_memory_handles_null_fields(self):
console, buf = _make_console()
format_single_memory(
console,
{"id": None, "memory": None, "text": "Fallback memory", "created_at": None},
"text",
)
output = buf.getvalue()
assert "Fallback memory" in output
assert "ID:" not in output
class TestAddResult:
def test_format_add_result_text(self):
-46
View File
@@ -1,46 +0,0 @@
"""Tests for the Platform backend (mem0 Platform API client)."""
from __future__ import annotations
from unittest.mock import patch
from mem0_cli.backend.platform import PlatformBackend
from mem0_cli.config import PlatformConfig
def _make_backend() -> PlatformBackend:
# api_key/base_url are only used to build the httpx client; every test here
# patches _request, so no real network calls are made.
return PlatformBackend(PlatformConfig(api_key="test-key", base_url="https://api.mem0.ai"))
class TestDeleteEntities:
def test_multiple_entities_returns_all_results(self):
backend = _make_backend()
responses = {
"/v2/entities/user/alice/": {"message": "user deleted"},
"/v2/entities/agent/bob/": {"message": "agent deleted"},
}
with patch.object(backend, "_request") as mock_request:
mock_request.side_effect = lambda method, path, **kw: responses[path]
result = backend.delete_entities(user_id="alice", agent_id="bob")
# Regression: previously only the last entity's response survived.
assert result == {
"user": {"message": "user deleted"},
"agent": {"message": "agent deleted"},
}
assert mock_request.call_count == 2
def test_single_entity_keyed_by_type(self):
backend = _make_backend()
with patch.object(backend, "_request", return_value={"message": "user deleted"}):
result = backend.delete_entities(user_id="alice")
assert result == {"user": {"message": "user deleted"}}
def test_no_entities_raises(self):
backend = _make_backend()
import pytest
with pytest.raises(ValueError):
backend.delete_entities()
-80
View File
@@ -1,80 +0,0 @@
"""Tests for telemetry subprocess secret handling."""
from __future__ import annotations
import io
import json
import subprocess
import sys
from mem0_cli.config import Mem0Config, save_config
from mem0_cli.telemetry import capture_event
from mem0_cli.telemetry_sender import _load_context
class _CaptureStdin:
def __init__(self):
self.buffer = ""
self.closed = False
def write(self, value: str) -> None:
self.buffer += value
def close(self) -> None:
self.closed = True
class _DummyProcess:
def __init__(self):
self.stdin = _CaptureStdin()
def test_capture_event_writes_context_to_stdin_not_argv(isolate_config, monkeypatch):
config = Mem0Config()
config.platform.api_key = "m0-test-secret"
config.telemetry.anonymous_id = "cli-anon-test"
save_config(config)
captured: dict[str, object] = {}
proc = _DummyProcess()
def fake_popen(args, **kwargs):
captured["args"] = args
captured["kwargs"] = kwargs
return proc
monkeypatch.setattr("mem0_cli.telemetry.subprocess.Popen", fake_popen)
capture_event("unit_test_event", {"case": "stdin-secret"})
argv = captured["args"]
assert argv == [sys.executable, "-m", "mem0_cli.telemetry_sender"]
assert all("m0-test-secret" not in arg for arg in argv)
kwargs = captured["kwargs"]
assert kwargs["stdin"] == subprocess.PIPE
assert kwargs["text"] is True
ctx = json.loads(proc.stdin.buffer)
assert ctx["mem0_api_key"] == "m0-test-secret"
assert ctx["payload"]["event"] == "unit_test_event"
assert proc.stdin.closed
def test_load_context_reads_from_stdin(monkeypatch):
monkeypatch.setattr("sys.argv", ["telemetry_sender"])
monkeypatch.setattr("sys.stdin", io.StringIO('{"payload": {"event": "stdin"}}'))
ctx = _load_context()
assert ctx["payload"]["event"] == "stdin"
def test_load_context_falls_back_to_argv(monkeypatch):
monkeypatch.setattr("sys.argv", ["telemetry_sender", '{"payload": {"event": "argv"}}'])
monkeypatch.setattr("sys.stdin", io.StringIO(""))
ctx = _load_context()
assert ctx["payload"]["event"] == "argv"
@@ -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",
+1 -10
View File
@@ -4,7 +4,7 @@ description: "Add facts, messages, or metadata to a user memory store with async
openapi: post /v3/memories/add/
---
Extract and store memories from a conversation using the V3 additive pipeline. The endpoint uses single-pass ADD-only extraction: one LLM call, no UPDATE/DELETE. Memories accumulate over time; nothing is overwritten.
Extract and store memories from a conversation using the V3 additive pipeline. The endpoint uses single-pass ADD-only extraction — one LLM call, no UPDATE/DELETE. Memories accumulate over time; nothing is overwritten.
## Endpoint
@@ -50,7 +50,6 @@ Provide conversation messages for Mem0 to extract memories from. At least one en
| `app_id` | string | No* | Associates the memory with an app. |
| `metadata` | object | Optional | Custom key/value metadata (e.g., `{"topic": "preferences"}`). |
| `infer` | boolean (default `true`) | Optional | Set to `false` to skip inference and store the provided text as-is. |
| `expiration_date` | string | Optional | Date in `YYYY-MM-DD` format. The memory is visible through this date and hidden by default after it passes. |
> \* At least one entity ID (`user_id`, `agent_id`, `app_id`, or `run_id`) is required.
@@ -84,11 +83,3 @@ The request is queued for background processing. The response contains an `event
<Info>
Poll the event status via `GET /v1/event/{event_id}/`. Status will be `SUCCEEDED` or `FAILED` once processing completes.
</Info>
<Info>
Memories with `expiration_date` remain stored after they expire. Search and get-all hide them by default; pass `show_expired: true` to include them.
</Info>
<Info>
Python uses `expiration_date`; TypeScript uses `expirationDate`.
</Info>
@@ -4,4 +4,4 @@ description: "Submit an export job to create a structured memory export using a
openapi: post /v1/exports/
---
Submit a job to create a structured export of memories using a customizable Pydantic schema. This process may take some time to complete, especially if you're exporting a large number of memories. You can tailor the export by applying various filters (e.g., `user_id`, `agent_id`, `app_id`, or `run_id`) and by modifying the Pydantic schema to ensure the final data matches your exact needs.
Submit a job to create a structured export of memories using a customizable Pydantic schema. This process may take some time to complete, especially if you're exporting a large number of memories. You can tailor the export by applying various filters (e.g., `user_id`, `agent_id`, `run_id`, or `session_id`) and by modifying the Pydantic schema to ensure the final data matches your exact needs.
+1 -8
View File
@@ -4,11 +4,7 @@ description: "Retrieve memories with paginated results and advanced filtering us
openapi: post /v3/memories/
---
List memories scoped by filters with paginated results. Entity IDs (`user_id`, `agent_id`, `app_id`, `run_id`) **must** be passed inside the `filters` object: top-level entity IDs are rejected with 400.
Expired memories are hidden by default. Pass `show_expired: true` to include memories whose `expiration_date` has passed.
Python uses `show_expired`; TypeScript uses `showExpired`.
List memories scoped by filters with paginated results. Entity IDs (`user_id`, `agent_id`, `app_id`, `run_id`) **must** be passed inside the `filters` object — top-level entity IDs are rejected with 400.
The `filters` object supports complex logical operations (AND, OR, NOT) and comparison operators:
@@ -36,7 +32,6 @@ memories = client.get_all(
}
]
},
show_expired=False,
page=1,
page_size=50
)
@@ -51,14 +46,12 @@ memories = client.get_all(
{
"id": "f4cbdb08-7062-4f3e-8eb2-9f5c80dfe64c",
"memory": "Alex is planning a trip to San Francisco from July 1st to July 10th",
"expiration_date": null,
"created_at": "2024-07-01T12:00:00Z",
"updated_at": "2024-07-01T12:00:00Z"
},
{
"id": "a2b8c3d4-5e6f-7g8h-9i0j-1k2l3m4n5o6p",
"memory": "Alex prefers vegetarian restaurants",
"expiration_date": null,
"created_at": "2024-07-05T15:30:00Z",
"updated_at": "2024-07-05T15:30:00Z"
}
@@ -4,4 +4,4 @@ description: "Retrieve the latest structured memory export after submitting an e
openapi: post /v1/exports/get
---
Retrieve the latest structured memory export after submitting an export job. You can filter the export by `user_id`, `agent_id`, `app_id`, `run_id`, `created_at`, or `updated_at` to get the most recent export matching your filters.
Retrieve the latest structured memory export after submitting an export job. You can filter the export by `user_id`, `run_id`, `session_id`, or `app_id` to get the most recent export matching your filters.
+7 -13
View File
@@ -4,13 +4,9 @@ description: "Search memories with hybrid retrieval (semantic + BM25 + entity ma
openapi: post /v3/memories/search/
---
Relevance-ranked hybrid search across stored memories. V3 uses multi-signal retrieval: semantic, BM25 keyword, and entity matching scored in parallel and fused. The returned `score` is a combined `[0, 1]` value.
Relevance-ranked hybrid search across stored memories. V3 uses multi-signal retrieval — semantic, BM25 keyword, and entity matching scored in parallel and fused. The returned `score` is a combined `[0, 1]` value.
Entity IDs (`user_id`, `agent_id`, `app_id`, `run_id`) **must** be passed inside the `filters` object: top-level entity IDs are rejected with 400. At least one entity ID is required.
Expired memories are hidden by default. Pass `show_expired: true` to include memories whose `expiration_date` has passed.
Python uses `show_expired`; TypeScript uses `showExpired`.
Entity IDs (`user_id`, `agent_id`, `app_id`, `run_id`) **must** be passed inside the `filters` object — top-level entity IDs are rejected with 400. At least one entity ID is required.
The `filters` object supports complex logical operations (AND, OR, NOT) and comparison operators:
- `in`: Matches any of the values specified
@@ -24,17 +20,16 @@ The `filters` object supports complex logical operations (AND, OR, NOT) and comp
### Search parameter defaults
| Parameter | Default |
| --- | --- |
| `top_k` | `10` (range 1–1000) |
| `threshold` | `0.1` (pass `0.0` to disable) |
| `rerank` | `false` (pass `true` to enable) |
| Parameter | V1/V2 | V3 |
| --- | --- | --- |
| `top_k` | Supported (default 10) | Supported (1-1000, default 10) |
| `threshold` | No default | Default `0.1` (pass `0.0` to disable) |
| `rerank` | Default `true` | Default `false` (pass `true` to enable) |
<CodeGroup>
```python Platform API Example
related_memories = client.search(
query="What are Alice's hobbies?",
show_expired=False,
filters={
"OR": [
{
@@ -59,7 +54,6 @@ related_memories = client.search(
"category": "hobbies"
},
"score": 0.82,
"expiration_date": null,
"created_at": "2024-07-26T10:29:36.630547-07:00",
"updated_at": null,
"categories": ["hobbies"]
+2 -11
View File
@@ -1,14 +1,5 @@
---
title: 'Update Memory'
description: "Update the content, metadata, timestamp, or expiration date of a single memory by its unique ID using the PUT endpoint."
description: "Update the content or metadata of a single memory by its unique ID using the PUT endpoint."
openapi: put /v1/memories/{memory_id}/
---
Use this endpoint to update mutable memory fields. To make a memory expire, set `expiration_date` to a `YYYY-MM-DD` date. To make it permanent again, send `expiration_date: null`.
```python
client.update("mem_123", expiration_date="2030-01-31")
client.update("mem_123", expiration_date=None)
```
TypeScript uses `expirationDate`.
---
@@ -1,5 +0,0 @@
---
title: "Remove Organization Member"
description: "Remove a member from an organization to revoke their access to its projects and resources."
openapi: "delete /api/v1/orgs/organizations/{org_id}/members/"
---
@@ -1,5 +0,0 @@
---
title: "Update Organization Member"
description: "Update an existing member's role within an organization to change their permissions and access level."
openapi: "put /api/v1/orgs/organizations/{org_id}/members/"
---
+3 -42
View File
@@ -14,7 +14,7 @@ Organizations and projects are **optional** features. You can use Mem0 without t
## Key Capabilities
- **Multi-org/project Support**: Organization and project are resolved automatically from your API key via `/v1/ping/`: no org or project params are accepted by `MemoryClient.__init__`. Use a project-specific API key to target a particular project.
- **Multi-org/project Support**: Specify organization and project when initializing the Mem0 client to attribute API usage appropriately
- **Member Management**: Control access to data through organization and project membership
- **Access Control**: Only members can access memories and data within their organization/project scope
- **Team Isolation**: Maintain data separation between different teams and projects for secure collaboration
@@ -79,7 +79,7 @@ new_project = client.project.create(
### Update Project Settings
Modify project configuration including custom instructions, categories, language preferences, retrieval criteria, and memory decay:
Modify project configuration including custom instructions, categories, graph settings, and language preferences:
```python
# Update project with custom categories
@@ -98,17 +98,6 @@ client.project.update(
# Use the input language for memory storage and retrieval
client.project.update(multilingual=True)
# Set retrieval criteria to control which memories are surfaced in search
client.project.update(
retrieval_criteria=[
{"name": "relevance", "description": "How directly relevant this memory is to the current topic or user query", "weight": 3},
{"name": "access_frequency", "description": "How often this memory has been accessed or surfaced recently", "weight": 1}
]
)
# Enable Memory Decay (boosts recently-accessed memories at search time)
client.project.update(decay=True)
# Update multiple settings at once
client.project.update(
custom_instructions="...",
@@ -120,37 +109,9 @@ client.project.update(
)
```
#### Set Retrieval Criteria
`retrieval_criteria` is a per-project list of dictionaries (`List[Dict]`) that shapes how memories are ranked and filtered during search. Each dictionary has three fields: `name` (identifier), `description` (interpreted by the LLM to score each memory), and `weight` (relative influence on the final score). Use this to focus retrieval on intent-aligned or signal-specific memories:
```python
client.project.update(
retrieval_criteria=[
{
"name": "joy",
"description": "Measure the intensity of positive emotions such as happiness, excitement, or amusement expressed in the memory. A higher score reflects greater joy.",
"weight": 3
},
{
"name": "curiosity",
"description": "Assess the extent to which the memory reflects inquisitiveness or interest in exploring new information. A higher score reflects stronger curiosity.",
"weight": 2
},
{
"name": "access_frequency",
"description": "How often this memory has been accessed or surfaced recently.",
"weight": 1
}
]
)
```
Pass an empty list to clear all criteria and restore default retrieval behaviour.
#### Toggle Memory Decay
`decay` is a per-project boolean that turns on [Memory Decay](/platform/features/memory-decay): a search-time ranking bias that reinforces recently-accessed memories and gently dampens stale ones. The flag is `false` by default; set it via the same project-update endpoint:
`decay` is a per-project boolean that turns on [Memory Decay](/platform/features/memory-decay) — a search-time ranking bias that reinforces recently-accessed memories and gently dampens stale ones. The flag is `false` by default; set it via the same project-update endpoint:
```bash cURL
curl -X PATCH https://api.mem0.ai/api/v1/orgs/organizations/$ORG_ID/projects/$PROJECT_ID/ \
@@ -1,5 +0,0 @@
---
title: "Remove Project Member"
description: "Remove a member from a project to revoke their access to its memories, configuration, and resources."
openapi: "delete /api/v1/orgs/organizations/{org_id}/projects/{project_id}/members/"
---
@@ -1,5 +0,0 @@
---
title: "Update Project Member"
description: "Update an existing member's role within a project to change their permissions and access level."
openapi: "put /api/v1/orgs/organizations/{org_id}/projects/{project_id}/members/"
---
@@ -1,5 +0,0 @@
---
title: "Update Project"
description: "Update a project's settings, including name, custom instructions, and other configuration options."
openapi: "patch /api/v1/orgs/organizations/{org_id}/projects/{project_id}/"
---
+63 -140
View File
@@ -4,121 +4,16 @@ description: "Major product launches, headline features, and milestones for Mem0
mode: "wide"
---
<Update label="2026-06-27" description="SDK memory expiration">
**SDK Memory Expiration: Expiring Memories Across Python and TypeScript**
The latest SDK releases add first-class expiration controls to memory writes, updates, and reads, plus new TypeScript provider coverage for production deployments.
- **Python client updates:** `MemoryClient.update()` and `AsyncMemoryClient.update()` now accept `expiration_date`, including `None` to clear an existing expiration.
- **TypeScript client updates:** `AddMemoryOptions`, `update()`, and `Memory` now support `expirationDate`; `search()` and `getAll()` can include expired memories with `showExpired`.
- **New TypeScript LLM providers:** `MiniMaxLLM` and `LiteLLM` are now available for OpenAI-compatible MiniMax and LiteLLM proxy deployments.
- **PGVector deployment flexibility:** TypeScript PGVector config now supports `connectionString` and `ssl`, so apps can use a managed Postgres URI instead of separate connection fields.
See [SDK & Tools](/changelog/sdk) for version details and PR links.
</Update>
<Update label="2026-06-25" description="Mem0 Plugin v0.2.11">
**Mem0 Plugin: Shared Memory for Claude Code, Cursor, Codex, and Antigravity**
The shared Mem0 editor plugin is current through v0.2.11:
- **Automatic context injection:** File reads, bash errors, session resume prompts, and startup timelines can retrieve relevant memories automatically.
- **Project and global scopes:** Project-scoped memories remain the default, while `global_search` supports team-wide recall across users and app scopes.
- **Coding categories:** A 17-category coding taxonomy installs in the background and is cached per Mem0 account.
- **Reliable capture:** Auto-capture, compaction summaries, session summaries, and metadata defaults keep memories scoped and readable.
- **Editor correctness:** Telemetry now reports Claude Code, Cursor, Codex, and Antigravity separately with each editor's real plugin version.
</Update>
<Update label="2026-06-25" description="Antigravity Plugin v0.1.3">
**Antigravity Plugin: Mem0 for Google Antigravity**
Antigravity support in the shared Mem0 editor plugin family is current through v0.1.3:
- **Self-contained plugin:** Includes its own plugin manifest, MCP config, hooks, shared scripts, and skills.
- **AGENTS.md convention:** Uses Antigravity's `contextFileName: "AGENTS.md"` convention.
- **Lifecycle hooks:** Wires session start, prompt recall, file-read context, memory-tool metadata enforcement, bash-error lookup, post-tool tracking, and stop summaries.
- **Shared memory layer:** Reuses the Mem0 Platform MCP tools and the shared 16-skill command bundle.
- **Better automatic recall:** v0.1.3 adds reranked injected context and clean `files_touched` metadata in session summaries.
- **Telemetry correctness:** v0.1.2 reports Antigravity as `antigravity` with the plugin's own version.
</Update>
<Update label="2026-06-22" description="OpenCode Plugin v0.2.0">
**OpenCode Plugin: Native SDK Memory Tools for OpenCode**
`@mem0/opencode-plugin` adds memory to OpenCode and is current through v0.2.0:
- **Native SDK tools:** Memory tools register through `@opencode-ai/plugin` and call the `mem0ai` SDK directly, so the plugin no longer depends on `mcp.mem0.ai`.
- **Memory scopes:** Operations support `project`, `session`, and `global` scope, with `/mem0-scope` to change the default.
- **Automatic context:** File-context injection, structured compaction summaries, and a recent-activity timeline surface relevant memories without manual recall.
- **Auto-dream consolidation:** Gated consolidation merges duplicates, drops stale or sensitive entries, and rewrites vague memories.
- **Skills load in place:** The `config` hook adds bundled skills to `skills.paths` instead of copying them into user config directories.
- **Safety controls:** Blocks `MEMORY.md` writes and redacts secrets before storing memories.
</Update>
<Update label="2026-06-12" description="Pi Agent Plugin v0.1.2">
**Pi Agent Plugin: Persistent Memory for Pi Agent**
`@mem0/pi-agent-plugin` adds semantic memory to Pi Agent and has been updated through v0.1.2:
- **Agent memory tool:** Registers `mem0_memory` for scoped search, add, get, delete, and delete-all operations.
- **Slash commands:** Adds `/mem0-remember`, `/mem0-search`, `/mem0-forget`, `/mem0-tour`, `/mem0-dream`, `/mem0-pin`, `/mem0-scope`, and `/mem0-status`.
- **Auto-capture:** Stores user and assistant memories after agent turns.
- **Dream consolidation:** Merges duplicates, resolves contradictions, and prunes stale memories behind session, time, and memory-count gates.
- **Project scoping:** Uses git-root detection for stable `app_id` values across monorepos.
- **Relevant command results:** v0.1.2 adds visible command feedback and thresholded, reranked search for search, forget, and pin commands.
</Update>
<Update label="2026-06-12" description="OpenClaw v1.0.13">
**OpenClaw Plugin: Current Memory Backend for OpenClaw**
`@mem0/openclaw-mem0` is current through v1.0.13, with the original production-ready memory backend plus newer setup, security, and runtime work:
- **Skills-based memory architecture:** Triage, recall, and dream skills handle extraction, recall, consolidation, and tool guidance.
- **Chat and CLI setup:** Supports chat-based platform setup, `openclaw mem0 init`, direct API keys, email OTP, autonomous agent setup, and OSS onboarding.
- **Platform and OSS modes:** Works with Mem0 Platform or self-hosted OSS providers including OpenAI, Anthropic, Ollama, Qdrant, and PGVector.
- **Agent-friendly CLI:** All 16 CLI commands support `--json` for machine-driven setup and diagnostics.
- **Runtime integration:** Exposes OpenClaw memory capability APIs for search manager and backend config status.
- **Security and compliance:** Added path containment checks, sensitive config metadata, dependency overrides, telemetry hashing, and metadata-only registration safety.
</Update>
<Update label="2026-06-10" description="Vercel AI SDK Provider v3.0.0">
**Vercel AI SDK Provider: Memory-Augmented Generation for AI SDK v6**
The Vercel AI SDK provider moved to the v6 provider contract and Mem0 v3 APIs:
- **AI SDK v6 support:** Migrated to `LanguageModelV3` / `ProviderV3`, including v3 stream lifecycle events and content arrays.
- **Mem0 v3 API support:** Memory writes and searches now use `/v3/memories/add/` and `/v3/memories/search/`.
- **Mem0 sources in responses:** `generateText` and `streamText` responses include memories as sources with `providerMetadata.mem0.memories`.
- **Safer prompt handling:** Prompts are cloned before memory injection, avoiding caller-side mutation.
- **Async storage fix:** `addMemories` is awaited so generated memories are not silently dropped.
- **Raw memory utilities:** Exports `searchMemories`, `retrieveMemories`, `getMemories`, and `addMemories` for apps that need direct memory control.
- **Deployment controls:** Per-request `mem0ApiKey` and `host` support Mem0 Platform, custom API keys, and self-hosted API endpoints.
</Update>
<Update label="2026-05-13" description="Temporal Reasoning for Mem0 Platform v3">
**Temporal Reasoning: Time-Aware Retrieval for Platform v3**
**Temporal Reasoning — Time-Aware Retrieval for Platform v3**
Mem0 Platform v3 can now interpret time-aware memories and queries so assistants retrieve the right information for questions about the past, upcoming plans, and current state.
- **Search intent parsing:** Queries like `last week`, `upcoming`, `right now`, and `as of March 2025` now resolve against memory timestamps automatically.
- **Default v3 behavior:** No per-request toggle is needed for v3 writes or searches.
- **Deterministic testing:** Pass `reference_date` to anchor relative phrases in tests, backfills, and demos.
- **Stable API shape:** Temporal reasoning changes ranking, not the client response contract.
- **Time-aware search intent** — Queries like `last week`, `upcoming`, `right now`, and `as of March 2025` return contextually appropriate results automatically
- **Enabled by default** — No per-request toggle required for v3 writes or searches
- **Anchored relative queries** — `reference_date` anchors relative search phrases for tests, backfills, and reproducible demos
- **Normal response shape** — Temporal reasoning affects ranking while preserving existing client response patterns
See [Temporal Reasoning](/platform/features/temporal-reasoning) for usage details.
@@ -126,11 +21,11 @@ See [Temporal Reasoning](/platform/features/temporal-reasoning) for usage detail
<Update label="2026-05-08" description="Memory Decay">
**Memory Decay: Recently-Used Memories Surface Higher**
**Memory Decay — Recently-Used Memories Surface Higher, Automatically**
Per-project search-time ranking bias that boosts recently-touched memories and gently dampens stale ones. Off by default; opt in per project via the `decay` field on the project endpoint, or via `client.project.update(decay=True)` in the SDKs (Python `v2.0.2` / TypeScript `v3.0.3`).
- **Soft bias, never a filter.** The scaling factor stays in `0.3×–1.5×`. Decay can reorder candidates but never removes them; anything that surfaced before decay can still surface after.
- **Soft bias, never a filter.** The scaling factor stays in `0.3×–1.5×`. Decay can reorder candidates but never zeros them out — anything that surfaced before decay can still surface after.
- **Reinforcement loop.** Every memory returned in a search has its access history updated, so frequently-used facts naturally float to the top over time.
- **Public score still clamped to `[0, 1]`.** Existing API contract preserved; no client-side changes needed.
- **v3 search only**, fully reversible. See [Memory Decay docs](/platform/features/memory-decay).
@@ -139,48 +34,76 @@ Per-project search-time ranking bias that boosts recently-touched memories and g
<Update label="2026-04-14" description="Mem0 SDK v2.0.0 / v3.0.0">
**New Memory Algorithm: State-of-the-Art Accuracy at ~3-4x Lower Cost**
**New Memory Algorithm — State-of-the-Art Accuracy at ~3-4x Lower Cost**
Ground-up rewrite of the memory pipeline with 20+ point benchmark improvements:
- **LoCoMo:** 71.4 → **91.6** (+20) for multi-turn conversation recall.
- **LongMemEval:** 67.8 → **93.4** (+26) for long-term memory across sessions.
- **BEAM (1M tokens):** **64.1** on production-scale memory evaluation.
- **Agent memories:** Assistant recall moves from 46% to **100%**.
- **Temporal reasoning:** "Where did I live before SF?" improves from 51% to **93%**.
- **Lower token use:** Retrieval stays under 7K tokens versus 25K+ for full-context approaches.
- **ADD-only extraction:** Memories accumulate; nothing is overwritten or deleted.
- **Hybrid retrieval:** Semantic search, BM25 keyword search, and entity boost are scored in parallel.
- **Graph memory (built-in)**: entities extracted, embedded, and linked across memories, with no external graph store required
- **LoCoMo:** 71.4 → **91.6** (+20) — multi-turn conversation recall
- **LongMemEval:** 67.8 → **93.4** (+26) — long-term memory across sessions
- **BEAM (1M tokens):** **64.1** — production-scale memory evaluation
- **Agent memories are first-class** — Previous algorithm: 46% on assistant recall. New: **100%**
- **Temporal reasoning works** — "Where did I live before SF?" Previous: 51%. New: **93%**
- **~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
- **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>
<Update label="2026-04-06" description="Mem0 Skill Graph">
**Mem0 Skill Graph: In-Context Documentation for AI Agents**
**Mem0 Skill Graph — In-Context Documentation for AI Agents**
AI coding agents in Claude Code, Cursor, and Codex can now access Mem0 knowledge directly in their workflow without leaving the editor. Three interconnected skills launched:
AI coding agents in Claude Code, Cursor, and Codex can now access Mem0 knowledge directly in their workflow — no doc searching required. Three interconnected skills launched:
- **mem0 Core Skill:** Python and TypeScript SDK reference, REST API patterns, and integration guides for LangChain, CrewAI, Autogen, and more.
- **mem0-cli Skill:** Terminal command reference, configuration walkthroughs, and CI/CD recipes.
- **mem0-vercel-ai-sdk Skill:** Vercel AI SDK provider API, memory-augmented generation patterns, and multi-provider setup.
- **mem0 Core Skill** — Complete Python and TypeScript SDK reference, REST API patterns, and integration guides for LangChain, CrewAI, Autogen, and more
- **mem0-cli Skill** — Terminal command reference, configuration walkthroughs, and CI/CD recipes
- **mem0-vercel-ai-sdk Skill** — Vercel AI SDK provider API, memory-augmented generation patterns, and multi-provider setup
</Update>
<Update label="2026-04-06" description="Mem0 CLI v0.2.2">
**Official Mem0 CLI: Now on PyPI and npm**
**Official Mem0 CLI — Now on PyPI and npm**
A full-featured command-line interface for Mem0, available in both Python and Node.js:
- **Install:** `pip install mem0-cli` or `npm install -g @mem0/cli`
- **Full command suite:** `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`, `event`.
- **Interactive setup:** `mem0 init` supports email verification and direct API key entry.
- **Runtime coverage:** Works with Mem0 Platform and self-hosted OSS modes.
- **Automation support:** Use `--json` for CI/CD pipelines and agent workflows.
- **Dual implementation:** Same commands and behavior across Python and Node.js.
- **Full command suite** — `add`, `search`, `list`, `get`, `update`, `delete`, `import`, `config`, `init`, `status`, `entity`, `event`
- **Interactive setup** — `mem0 init` with email verification or direct API key entry
- **Works everywhere** — Platform (Mem0 Cloud) and self-hosted OSS modes
- **Scriptable** — `--json` flag for CI/CD pipelines and automation
- **Dual SDK** — Same commands, same experience across Python and Node.js
</Update>
<Update label="2026-04-06" description="OpenClaw v1.0.4">
**OpenClaw Plugin — Production-Ready**
The OpenClaw Mem0 plugin went from initial release to production-ready in one week (v1.0.0 → v1.0.4):
- **Skills-based memory architecture** — New extraction pipeline with skill-loader, batched extraction, and domain-aware memory triage
- **Dream gate** — Automatic memory consolidation during idle periods for higher-quality long-term recall
- **Interactive CLI** — `openclaw mem0 init`, `status`, `config`, `import`, and `event` commands
- **Unified tool naming** — `memory_add` and `memory_delete` replace 4 legacy tools, matching the platform API
- **Security hardened** — Path traversal protection, pinned dependencies, 329 tests across 10 files
</Update>
<Update label="2026-04-02" description="Mem0 Plugin for AI Editors">
**Mem0 Plugin for Claude Code, Cursor, and Codex**
Launched a unified Mem0 plugin across three major AI development environments — Claude Code and Cursor first (March 25), then Codex (April 2):
- **9 MCP memory tools** — add, search, get, update, delete, bulk delete, entity management via `mcp.mem0.ai`
- **Lifecycle hooks** — Automatic memory capture at session start, context compaction, task completion, and session end
- **Cloud MCP server** — Managed endpoint replaces local MCP and Smithery setup
- **Streamable HTTP transport** — New MCP transport protocol for real-time streaming
- **Codex-specific skill** — Dedicated skill in `mem0-plugin/skills/mem0-codex` for Codex workflows
</Update>
@@ -190,11 +113,11 @@ A full-featured command-line interface for Mem0, available in both Python and No
Major expansion of the provider ecosystem:
- **Apache AGE:** New graph store support, bringing the total to 4 graph store backends (Neo4j, Memgraph, Kuzu, Apache AGE). **Note:** All external graph store backends (Neo4j, Memgraph, Kuzu, Apache AGE) were subsequently removed in v2.0.0 (2026-04-14). Graph memory is now built-in entity linking with no external graph store required; see the [v2.0.0 entry above](#mem0-sdk-v2-0-0-v3-0-0).
- **Turbopuffer:** New vector database provider for Python SDK.
- **MiniMax:** New LLM provider with dedicated AWS Bedrock support.
- **pgvector for Node.js:** PostgreSQL vector support added to the TypeScript OSS SDK.
- **Reasoning models:** `reasoning_effort` parameter for OpenAI o1/o3-style models.
- **Apache AGE** — New graph store support, bringing the total to 4 graph store backends (Neo4j, Memgraph, Kuzu, Apache AGE)
- **Turbopuffer** — New vector database provider for Python SDK
- **MiniMax** — New LLM provider with dedicated AWS Bedrock support
- **pgvector for Node.js** — PostgreSQL vector support added to the TypeScript OSS SDK
- **Reasoning models** — `reasoning_effort` parameter for OpenAI o1/o3-style models
</Update>
@@ -202,6 +125,6 @@ Major expansion of the provider ecosystem:
**Mem0 Platform Skill on skills.sh**
First skill launch: a dedicated Mem0 skill providing platform API reference, quickstart patterns, and integration examples directly inside agent sessions. Available on [skills.sh](https://skills.sh) for any compatible AI coding agent.
First skill launch — a dedicated Mem0 skill providing platform API reference, quickstart patterns, and integration examples directly inside agent sessions. Available on [skills.sh](https://skills.sh) for any compatible AI coding agent.
</Update>
+303
View File
@@ -0,0 +1,303 @@
---
title: "OpenClaw"
description: "Release notes for the OpenClaw plugin and agent harness."
mode: "wide"
---
<Update label="2026-04-29" description="v1.0.11">
**New Features:**
- **Skills-mode auto-setup:** `enableSkillsConfig()` now runs automatically after onboarding — enables triage, recall (with reranking + keyword search), and dream consolidation with `tools.profile = "full"` and disables the built-in session-memory hook to avoid conflicts
- **Memory runtime capability:** Plugin now exposes `runtime.getMemorySearchManager()` and `resolveMemoryBackendConfig()` on the registered memory capability, enabling OpenClaw gateway to query memory status and backend config directly
- **Dimension-aware collections:** OSS wizard detects embedder dimension changes and creates a new collection (`mem0_<dims>d`) automatically, with a warning about old memories being inaccessible under the new embedder
- **Tool documentation in skills:** Both `memory-triage` and `memory-dream` SKILL.md files now include full tool reference sections listing all available tools with parameters
**Improvements:**
- **Auto-capture and auto-recall default to enabled:** `autoCapture` and `autoRecall` now default to `true` (was `false`). Manifest descriptions updated accordingly. Ignored in skills mode
- **`memory_update` over delete+add:** Skills now prefer `memory_update` for in-place edits — atomic and preserves edit history. Consolidation pattern updated: update best memory, delete redundant ones
- **Search threshold lowered:** Default `searchThreshold` reduced from `0.5` to `0.1` for broader recall. Removed hardcoded `0.6` recall-specific override — all searches now use the configured threshold
- **Embedder dimension propagation:** Vector store config auto-resolves dimensions from embedder config when not explicitly set. Syncs `dimension` and `embeddingModelDims` fields for Qdrant/PGVector compatibility
- **Config file write safety:** `writeFullConfig()` now re-reads and deep-merges the `plugins` section before writing, preserving `installs` and `slots` written by the OpenClaw gateway
- **Additional embedder models:** Added `mxbai-embed-large` (1024), `all-minilm` (384), and `snowflake-arctic-embed` (1024) to known embedder dimensions
**Security:**
- Bumped `protobufjs` to `>=7.5.5` via pnpm overrides (GHSA-xq3m-2v4x-88gg) ([#5012](https://github.com/mem0ai/mem0/pull/5012))
**Fixes:**
- Moved `bootstrapTelemetryFlag()` and removed `ensureInstallRecord()` from module-level side effects — both now run inside `register()` to avoid crashes when loaded outside OpenClaw gateway
- Fixed OSS history DB path resolution: absolute paths no longer passed through `resolvePath()`, preventing double-prefix bugs
- Manifest `providerAuthEnvVars` replaced with spec-compliant `setup.providers` format using `id` + `envVars`
**Dependencies:**
- Bumped `mem0ai` from `3.0.1` to `3.0.2`
- Bumped `pluginApi` and `minGatewayVersion` compat to `>=2026.4.24`
</Update>
<Update label="2026-04-23" description="v1.0.10">
**Security:**
- Telemetry `distinct_id` now uses SHA-256 instead of MD5 — prevents rainbow-table reversal of API key hashes
- User email is now SHA-256 hashed before sending as `distinct_id` — no PII in telemetry payloads
- Declared PostHog telemetry endpoint (`us.i.posthog.com`) in `providerEndpoints`
**Fixes:**
- Fixed version-pinned install records preventing plugin updates. `ensureInstallRecord()` now detects semver-pinned specs (e.g. `@mem0/openclaw-mem0@1.0.7`) and rewrites them to `@latest` or `clawhub:` prefix so `openclaw plugins update` resolves to the newest release
- Fixed `searchThreshold` default inconsistency: standardized to `0.3` across docs, README, and manifest
- `PLUGIN_VERSION` now injected at build time via tsup `define` from `package.json` — no more hardcoded version strings
**Manifest Compliance:**
- Removed non-spec fields: `requiredEnvVars`, `dataLocations`, `privacy`, `setup` (with `externalEndpoints`, `providers`, `requiresRuntime`, `postInstallHint`)
- Replaced `setup.externalEndpoints` with spec-compliant `providerEndpoints` using `endpointClass` + `hosts` format
- Env var declarations now rely solely on `providerAuthEnvVars` (already spec-compliant)
**Docs:**
- Fixed `openclaw plugins update` command: uses plugin ID (`openclaw-mem0`), not npm package name (`@mem0/openclaw-mem0`)
- Added update section to README
- Removed redundant "Key Features" and "Conclusion" sections from integration docs
</Update>
<Update label="2026-04-22" description="v1.0.9">
**Security & Compliance:**
- Added top-level `requiredEnvVars` to plugin manifest, declaring env vars per mode (platform, OSS OpenAI, OSS Anthropic, OSS Ollama). Fixes ClaHub scanner "required env vars: none" mismatch
- Added `sensitive: true` and descriptions to `apiKey` and `userEmail` in `configSchema` — previously only declared in `uiHints`
- Added `default: false` with descriptions to `autoCapture` and `autoRecall` in `configSchema` so scanner can confirm opt-in defaults
- Added `dataLocations` field to manifest declaring all persistence paths (config, vectorStore, historyDb, dreamState)
- Added `privacy` field to manifest documenting data flow for platform vs open-source mode and credential storage guidance
- Added `externalEndpoints` to `setup` section declaring api.mem0.ai and app.mem0.ai with purpose and requirement context
**Tests:**
- Replaced direct `process.env` access in `tests/cli-commands.test.ts` and `tests/fs-safe.test.ts` with `vi.stubEnv`/`vi.unstubAllEnvs`. Fixes ClaHub static analysis flag for "environment variable access combined with network send"
- 421 tests across 15 test files
</Update>
<Update label="2026-04-21" description="v1.0.8">
**New Features:**
- **OSS Onboarding Wizard:** New guided 4-step interactive setup for open-source mode — walks through LLM provider, embedding provider, vector store, and user ID selection with prefilled defaults
- **Agent-Friendly CLI:** Added `--json` flag to all 16 CLI commands for machine-readable output. Agents can call `openclaw mem0 help --json` to discover every command and flag
- **Non-Interactive OSS Setup:** Added `--mode open-source` with `--oss-llm`, `--oss-embedder`, `--oss-vector` flags for fully automated OSS configuration without prompts
- **JSON Helpers Module:** New `cli/json-helpers.ts` with `jsonOut`, `jsonErr`, and `redactSecrets` utilities for consistent structured output
**Improvements:**
- **Init Flow Redesigned:** Replaced 3-option flat menu with 2-level structure: Platform (email login or API key) and Open Source (guided wizard)
- **Provider Selection:** LLM providers: OpenAI, Ollama, Anthropic. Embedding providers: OpenAI, Ollama. Vector stores: Qdrant, PGVector
- **Input Prefill:** All prompts with defaults (base URL, user ID) now prefill the input field instead of showing defaults in brackets
- **Smart Reuse:** When LLM and embedder use the same provider, API key and base URL are automatically reused from the LLM step
- **Default Model:** Updated default LLM model to `gpt-5-mini`
- **Manifest Compliance:** Removed undocumented fields, aligned env var declarations between SKILL.md and manifest, fixed `configSchema.required` for clean installs
**Tests:**
- 404 tests across 15 test files (+3 new: `json-helpers.test.ts`, `oss-wizard.test.ts`, `cli-commands.test.ts`)
</Update>
<Update label="2026-04-20" description="v1.0.7">
**New Features:**
- **Chat-Based Setup:** Added chat-based Platform setup flow — users can now configure the plugin conversationally instead of editing config files manually
- **Installation Docs Rewrite:** Rewrote README and integration docs with chat-first setup, numbered manual steps.
**Improvements:**
- **SDK Upgrade:** Bumped `mem0ai` dependency to 3.0.1 for V3 API compatibility
- **Config Cleanup:** Dropped deprecated `orgId`, `projectId`, `enableGraph` config options; updated CLI prompts ([#4734](https://github.com/mem0ai/mem0/pull/4734), [#4764](https://github.com/mem0ai/mem0/pull/4764))
- **Noise Filtering:** Expanded noise patterns in memory add tool; handle leading text in JSON extraction
</Update>
<Update label="2026-04-11" description="v1.0.6">
**Bug Fixes:**
- **Telemetry:** Replaced shared `"anonymous-openclaw"` fallback with a persistent per-machine random hash (`openclaw-anon-<uuid>`), so anonymous plugin users are counted individually in PostHog ([#4790](https://github.com/mem0ai/mem0/pull/4790))
- **Telemetry:** Added PostHog `$identify` event on first authenticated run to stitch anonymous history onto the authenticated profile ([#4790](https://github.com/mem0ai/mem0/pull/4790))
- **Telemetry:** Fixed event loss on short-lived CLI invocations — added `beforeExit` handler to flush queued events before the process exits ([#4790](https://github.com/mem0ai/mem0/pull/4790))
- **Telemetry:** Added lazy `/v1/ping/` email resolution so users who configure API key outside `mem0 init` show as their email in PostHog, not an md5 hash ([#4790](https://github.com/mem0ai/mem0/pull/4790))
- **Telemetry:** Unified CLI event prefix from `openclaw.<cmd>` to `openclaw.cli.<cmd>` on the needsSetup branch to match the authenticated branch ([#4790](https://github.com/mem0ai/mem0/pull/4790))
**Improvements:**
- **API:** Added `source: "OPENCLAW"` to all provider calls (`add`, `search`, `getAll`) across tools, CLI commands, recall, and the OSS backend adapter ([#4790](https://github.com/mem0ai/mem0/pull/4790))
</Update>
<Update label="2026-04-07" description="v1.0.5">
**Bug Fixes:**
- **Init interactive choice bug**: Fixed number selection in `openclaw mem0 init` — entering 1/2/3 now correctly selects the corresponding option (was broken by readline prefill concatenating with user input)
- **OSS pgvector crash** ([#4727](https://github.com/mem0ai/mem0/issues/4727)): Fixed "Client has already been connected" cascade when using pgvector in OSS mode. The warmup call swallowed errors leaving a half-initialized pg client; concurrent recall/capture then all hit `client.connect()` on the same client. Fix: let warmup errors propagate (so `initPromise` resets and retries with a fresh Memory + fresh pg client) and build fresh config objects per attempt instead of mutating shared state.
**Removed:**
- **`orgId` / `projectId` config parameters**: Removed from config schema, CLI (`config show/get/set`), init display, and providers. The API key is project-scoped, so separate org/project IDs are unnecessary and could cause access errors if mismatched.
- **`enableGraph` config parameter**: Removed from all config surfaces, providers, backend, and tools. Graph memory is being deprecated — removing the flag avoids unnecessary exposure.
</Update>
<Update label="2026-04-04" description="v1.0.4">
**New Features:**
- **Interactive init flow**: `openclaw mem0 init` with interactive menu (email verification or direct API key). Non-interactive modes: `--api-key`, `--email`, `--email --code`
- **`memory_add` tool**: Replaces `memory_store` — name now matches `mem0` CLI and platform API
- **`memory_delete` tool**: Unified delete — single ID, search-then-delete, bulk, entity cascade. Replaces `memory_forget` and `memory_delete_all`
- **CLI subcommands**: `openclaw mem0 init`, `openclaw mem0 status`, `openclaw mem0 config show`, `openclaw mem0 config set`
- **`import` CLI command**: Bulk-import memories from a JSON file with `--user-id` and `--agent-id` overrides
- **`event list` / `event status` CLI commands**: Monitor background processing events
- **`fs-safe.ts` module**: Isolated filesystem wrappers in a separate entry point
- **`backend/` module**: `PlatformBackend` with direct HTTP API access for CLI commands
- **Plugin manifest**: Added `contracts.tools`, `configSchema`, and `uiHints` to `openclaw.plugin.json`
- **Test suite**: 329 tests across 10 test files
**Changes:**
- **Modular architecture**: Extracted tools into `tools/` directory (6 files) and CLI into `cli/commands.ts`
- **Code splitting**: tsup builds with `splitting: true` and two entry points
- **Skills updated**: All SKILL.md files reference new tool names (`memory_add`, `memory_delete`)
- **Auto-recall timeout**: Recall wrapped in 8-second `Promise.race`
- **Auto-capture fire-and-forget**: `provider.add()` runs in background via `.then()/.catch()`
- **Auto-capture minimum content gate**: Skips extraction when total user content is fewer than 50 chars
**Removed:**
- `memory_store` tool — replaced by `memory_add`
- `memory_forget` tool — replaced by `memory_delete`
- `memory_delete_all` tool — merged into `memory_delete`
- `memory_history` tool and `history` CLI command — deprecated
</Update>
<Update label="2026-04-03" description="v1.0.3">
**Bug Fixes:**
- **Security**: Added `safePath()` containment helper to `readSkillFile` and `readDomainOverlay` in `skill-loader.ts` — prevents directory traversal
- **Noise filter**: Reverted incorrect `After-Compaction` regex rename back to `Post-Compaction`
**Changes:**
- **Supply-chain hardening**: Pinned `mem0ai` dependency to exact `2.3.0` (was `^2.3.0`)
**Tests:**
- 12 new tests covering `safePath`, `readSkillFile`, `readDomainOverlay`, and `loadSkill` with traversal inputs
</Update>
<Update label="2026-04-02" description="v1.0.2">
**Bug Fixes:**
- **Security**: Removed `resolveEnvVars()` and `resolveEnvVarsDeep()` from `config.ts` — plugin-side env resolution was redundant and triggered static analysis warnings ([#4676](https://github.com/mem0ai/mem0/pull/4676))
</Update>
<Update label="2026-04-02" description="v1.0.1">
**New Features:**
- **CD workflow**: Added continuous deployment workflow with OIDC trusted publishing ([#4672](https://github.com/mem0ai/mem0/pull/4672))
- **Plugin configuration manifest**: Added `compat` and `build` metadata to `package.json` ([#4667](https://github.com/mem0ai/mem0/pull/4667))
- **LICENSE**: Added Apache-2.0 license file ([#4667](https://github.com/mem0ai/mem0/pull/4667))
**Bug Fixes:**
- **Dream gate**: Fixed cheap-first ordering, session isolation, and verified completion ([#4666](https://github.com/mem0ai/mem0/pull/4666))
- **Graceful startup**: Plugin now starts gracefully when no API key is configured ([#4669](https://github.com/mem0ai/mem0/pull/4669))
</Update>
<Update label="2026-04-01" description="v1.0.0">
**New Features:**
- **Skills-based memory architecture**: New skill-loader and skill-based extraction pipeline with batched extraction ([#4624](https://github.com/mem0ai/mem0/pull/4624))
- **Dream gate**: Memory consolidation and dream-cycle processing during idle periods
- **Enhanced recall**: New `recall.ts` module with improved recall logic and skill-aware retrieval
- **Memory triage skill**: Domain-aware memory triage with companion domain support and recall protocol
- **Memory dream skill**: Skill for memory consolidation during idle periods
- **Plugin configuration**: Added `openclaw.plugin.json` manifest and `scripts/configure.py` setup helper
**Changes:**
- Extraction pipeline refactored to use skills-based architecture for more contextual and higher quality memory capture
</Update>
<Update label="2026-03-26" description="v0.4.1">
**New Features:**
- **Improved extraction quality**: Enhanced noise filtering, deduplication, and better extraction instructions
**Bug Fixes:**
- **Credential detection**: Improved detection of credentials, API keys, and secrets in extraction instructions (#4552)
- **Standalone timestamps**: Prevented extraction of standalone timestamps as memories (#4550)
</Update>
<Update label="2026-03-16" description="v0.4.0">
**New Features:**
- **Non-interactive trigger filtering**: Skips recall and capture for `cron`, `heartbeat`, `automation`, and `schedule` triggers
- **Subagent hallucination prevention**: Detects ephemeral subagent sessions and routes recall to parent namespace
- **Dynamic recall thresholding**: Memories scoring less than 50% of top result are dropped
- **SQLite resilience**: Init error recovery with automatic retry for OSS mode
- **`disableHistory` config option**: New `oss.disableHistory` flag
- 78 unit tests covering filtering, isolation, trigger filtering, subagent detection, and SQLite resilience
**Changes:**
- Auto-recall threshold raised from 0.5 to 0.6 for stricter precision
- Recall candidate pool increased to `topK * 2` for better filtering headroom
- Relaxed extraction instructions: related facts kept together to preserve context
**Bug Fixes:**
- **Concurrent session race condition**: Lifecycle hooks now use `ctx.sessionKey` directly instead of a shared mutable variable
</Update>
<Update label="2026-03-12" description="v0.3.1">
**New Features:**
- **Message filtering pipeline**: Multi-stage noise removal before extraction
- **Broad recall for new sessions**: Short or new-session prompts trigger secondary broad search
- **Client-side threshold filtering**: Safety net that drops low-relevance results
- **Temporal anchoring**: Extraction instructions now include current date
- 55 unit tests covering filtering and isolation helpers
**Changes:**
- Extraction window expanded from last 10 to last 20 messages
- Rewritten custom extraction instructions for conciseness and deduplication
- Refactored monolithic `index.ts` (1772 lines) into 6 focused modules
</Update>
<Update label="2026-03-10" description="v0.3.0">
**Bug Fixes:**
- Updated `mem0ai` dependency with sqlite3 to better-sqlite3 migration (#4270)
</Update>
<Update label="2026-03-09" description="v0.2.0">
**New Features:**
- Per-agent memory isolation for multi-agent setups via `agentId`
- "Understanding userId" section in docs
**Changes:**
- Updated config examples to use concrete `userId` values instead of placeholders
**Bug Fixes:**
- Migrated platform search to Mem0 v2 API
</Update>
<Update label="2026-02-19" description="v0.1.2">
**New Features:**
- Source field for openclaw memory entries
**Bug Fixes:**
- Auto-recall injection and auto-capture message drop
</Update>
<Update label="2026-02-02" description="v0.1.0">
**New Features:**
- Initial release of the OpenClaw Mem0 plugin
- Platform mode (Mem0 Cloud) and open-source mode support
- Auto-recall: inject relevant memories before each turn
- Auto-capture: store facts after each turn
- Configurable `topK`, `threshold`, and `apiVersion` options
</Update>
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: "Platform"
description: "Release notes for the Mem0 hosted platform: backend, dashboard, billing, and infrastructure changes."
description: "Release notes for the Mem0 hosted platform — backend, dashboard, billing, and infrastructure changes."
mode: "wide"
---
@@ -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>
+49 -1071
View File
File diff suppressed because it is too large Load Diff
@@ -59,9 +59,5 @@ Here are the parameters available for configuring AWS Bedrock embedder:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `model` | The name of the embedding model to use | `amazon.titan-embed-text-v1` |
| `aws_region` | AWS region for the Bedrock client | `us-west-2` |
| `aws_access_key_id` | AWS access key ID for authentication | `None` |
| `aws_secret_access_key` | AWS secret access key for authentication | `None` |
| `aws_session_token` | AWS session token for temporary credentials | `None` |
</Tab>
</Tabs>
@@ -1,50 +0,0 @@
---
title: "FastEmbed"
description: "Configure FastEmbed as an embedding provider in Mem0 to generate embeddings locally using ONNX-based models without a GPU."
---
You can use FastEmbed to run embedding models locally in Mem0. FastEmbed is an ONNX-based embedding library that runs efficiently on CPU without requiring a GPU or an external API key.
### Installation
```bash
pip install fastembed
```
### Usage
<CodeGroup>
```python Python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your_api_key" # For LLM
config = {
"embedder": {
"provider": "fastembed",
"config": {
"model": "thenlper/gte-large"
}
}
}
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="john")
```
</CodeGroup>
### Config
Here are the parameters available for configuring FastEmbed embedder:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `model` | The name of the FastEmbed model to use | `thenlper/gte-large` |
| `embedding_dims` | Dimensions of the embedding model (auto-derived from the model if not set) | `None` |
@@ -67,15 +67,14 @@ Here are the parameters available for configuring Gemini embedder:
| Parameter | Description | Default Value |
| ---------------- | ------------------------------------ | ----------------------- |
| `model` | The name of the embedding model to use| `models/gemini-embedding-001` |
| `embedding_dims` | Dimensions of the embedding model | `768` |
| `embedding_dims` | Dimensions of the embedding model | `1536` |
| `api_key` | The Google API key | `None` |
| `output_dimensionality` | Output dimensionality for the embedding model (Gemini-specific; used when `embedding_dims` is not set) | `None` |
</Tab>
<Tab title="TypeScript">
| Parameter | Description | Default Value |
| ----------------- | --------------------------------------------- | -------------------------- |
| `model` | The name of the embedding model to use | `gemini-embedding-001` |
| `embeddingDims` | Dimensions of the embedding model. When not set, uses the model's native output dimensionality (3072 for `gemini-embedding-001`; MRL truncation to 768, 1536, or 3072 is supported) | `None` |
| `embeddingDims` | Dimensions of the embedding model | `1536` |
| `apiKey` | Google API key | `None` |
</Tab>
</Tabs>
@@ -16,7 +16,7 @@ config = {
"embedder": {
"provider": "lmstudio",
"config": {
"model": "nomic-ai/nomic-embed-text-v1.5-GGUF"
"model": "nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.f16.gguf"
}
}
}
@@ -37,6 +37,6 @@ Here are the parameters available for configuring LM Studio embedder:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `model` | The name of the LM Studio model to use | `nomic-ai/nomic-embed-text-v1.5-GGUF` |
| `model` | The name of the LM Studio model to use | `nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.f16.gguf` |
| `embedding_dims` | Dimensions of the embedding model | `1536` |
| `lmstudio_base_url` | Base URL for LM Studio connection | `http://localhost:1234/v1` |
+1 -2
View File
@@ -10,7 +10,7 @@ Mem0 offers support for various embedding models, allowing users to choose the o
See the list of supported embedders below.
<Note>
All embedders listed below are supported in the Python implementation. The TypeScript implementation supports: **OpenAI**, **Azure OpenAI**, **Google AI**, **Langchain**, **LM Studio**, and **Ollama**.
The following embedders are supported in the Python implementation. The TypeScript implementation currently only supports OpenAI.
</Note>
<CardGroup cols={4}>
@@ -24,7 +24,6 @@ See the list of supported embedders below.
<Card title="LM Studio" href="/components/embedders/models/lmstudio"></Card>
<Card title="Langchain" href="/components/embedders/models/langchain"></Card>
<Card title="AWS Bedrock" href="/components/embedders/models/aws_bedrock"></Card>
<Card title="FastEmbed" href="/components/embedders/models/fastembed"></Card>
</CardGroup>
## Usage
+2 -2
View File
@@ -98,7 +98,7 @@ Here's a comprehensive list of all parameters that can be used across different
| `max_tokens` | Tokens to generate | All |
| `top_p` | Probability threshold for nucleus sampling | All |
| `top_k` | Number of highest probability tokens to keep | All |
| `http_client_proxies`| Allow proxy server settings | All |
| `http_client_proxies`| Allow proxy server settings | AzureOpenAI |
| `models` | List of models | Openrouter |
| `route` | Routing strategy | Openrouter |
| `openrouter_base_url`| Base URL for Openrouter API | Openrouter |
@@ -110,7 +110,7 @@ Here's a comprehensive list of all parameters that can be used across different
| `deepseek_base_url` | Base URL for DeepSeek API | DeepSeek |
| `xai_base_url` | Base URL for XAI API | XAI |
| `sarvam_base_url` | Base URL for Sarvam API | Sarvam |
| `reasoning_effort` | Reasoning level (low, medium, high) | All |
| `reasoning_effort` | Reasoning level (low, medium, high) | Sarvam |
| `frequency_penalty` | Penalize frequent tokens (-2.0 to 2.0) | Sarvam |
| `presence_penalty` | Penalize existing tokens (-2.0 to 2.0) | Sarvam |
| `seed` | Seed for deterministic sampling | Sarvam |
+2 -2
View File
@@ -20,7 +20,7 @@ config = {
"llm": {
"provider": "anthropic",
"config": {
"model": "claude-sonnet-4-6",
"model": "claude-sonnet-4-20250514",
"temperature": 0.1,
"max_tokens": 2000,
}
@@ -45,7 +45,7 @@ const config = {
provider: 'anthropic',
config: {
apiKey: process.env.ANTHROPIC_API_KEY || '',
model: 'claude-sonnet-4-6',
model: 'claude-sonnet-4-20250514',
temperature: 0.1,
maxTokens: 2000,
},
+1 -1
View File
@@ -6,7 +6,7 @@ description: "Configure AWS Bedrock as an LLM provider in Mem0 with IAM authenti
### Setup
- Before using the AWS Bedrock LLM, make sure you have the appropriate model access from [Bedrock Console](https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/modelaccess).
- You will also need to authenticate the `boto3` client by using a method in the [AWS documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials)
- You will have to export `AWS_REGION`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` to set environment variables.
- You will have to export `AWS_REGION`, `AWS_ACCESS_KEY`, and `AWS_SECRET_ACCESS_KEY` to set environment variables.
### Usage
+1 -28
View File
@@ -7,8 +7,7 @@ To use DeepSeek LLM models, you have to set the `DEEPSEEK_API_KEY` environment v
## Usage
<CodeGroup>
```python Python
```python
import os
from mem0 import Memory
@@ -37,32 +36,6 @@ messages = [
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
```typescript TypeScript
import { Memory } from 'mem0ai/oss';
const config = {
llm: {
provider: 'deepseek',
config: {
apiKey: process.env.DEEPSEEK_API_KEY || '',
model: 'deepseek-chat',
temperature: 0.2,
maxTokens: 2000,
top_p: 1.0,
},
},
};
const memory = new Memory(config);
const 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."}
];
await memory.add(messages, { userId: 'alice', metadata: { category: 'movies' } });
```
</CodeGroup>
You can also configure the API base URL in the config:
```python
+2 -2
View File
@@ -21,7 +21,7 @@ config = {
"llm": {
"provider": "groq",
"config": {
"model": "llama-3.3-70b-versatile",
"model": "mixtral-8x7b-32768",
"temperature": 0.1,
"max_tokens": 2000,
}
@@ -46,7 +46,7 @@ const config = {
provider: 'groq',
config: {
apiKey: process.env.GROQ_API_KEY || '',
model: 'llama3-70b-8192',
model: 'mixtral-8x7b-32768',
temperature: 0.1,
maxTokens: 1000,
},
+1 -31
View File
@@ -4,12 +4,9 @@ description: "Use LiteLLM as an LLM provider in Mem0 to access over 100 language
---
[Litellm](https://litellm.vercel.app/docs/) is compatible with over 100 large language models (LLMs), all using a standardized input/output format. You can explore the [available models](https://litellm.vercel.app/docs/providers) to use with Litellm. Ensure you set the `API_KEY` for the model you choose to use.
In the TypeScript SDK, run LiteLLM as a [proxy server](https://docs.litellm.ai/docs/simple_proxy) (an OpenAI-compatible endpoint) and point Mem0 at it via `LITELLM_API_BASE` (defaults to `http://localhost:4000`).
## Usage
<CodeGroup>
```python Python
```python
import os
from mem0 import Memory
@@ -36,33 +33,6 @@ messages = [
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
```typescript TypeScript
import { Memory } from 'mem0ai/oss';
// Point Mem0 at your LiteLLM proxy. apiKey defaults to "sk-anything"
// (the proxy handles real auth); baseURL defaults to http://localhost:4000.
const config = {
llm: {
provider: 'litellm',
config: {
apiKey: process.env.LITELLM_API_KEY || 'sk-anything',
baseURL: process.env.LITELLM_API_BASE || 'http://localhost:4000',
model: 'gpt-5-mini',
},
},
};
const memory = new Memory(config);
const 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."}
];
await memory.add(messages, { userId: 'alice', metadata: { category: 'movies' } });
```
</CodeGroup>
## Config
All available parameters for the `litellm` config are present in [Master List of All Params in Config](../config).
+2 -45
View File
@@ -7,8 +7,7 @@ To use MiniMax LLM models, you have to set the `MINIMAX_API_KEY` environment var
## Usage
<CodeGroup>
```python Python
```python
import os
from mem0 import Memory
@@ -37,37 +36,9 @@ messages = [
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
```typescript TypeScript
import { Memory } from 'mem0ai/oss';
const config = {
llm: {
provider: 'minimax',
config: {
apiKey: process.env.MINIMAX_API_KEY || '',
model: 'MiniMax-M2.7',
temperature: 0.2,
maxTokens: 2000,
topP: 1.0,
},
},
};
const memory = new Memory(config);
const 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." },
];
await memory.add(messages, { userId: 'alice', metadata: { category: 'movies' } });
```
</CodeGroup>
You can also configure the API base URL in the config:
<CodeGroup>
```python Python
```python
config = {
"llm": {
"provider": "minimax",
@@ -80,20 +51,6 @@ config = {
}
```
```typescript TypeScript
const config = {
llm: {
provider: 'minimax',
config: {
model: 'MiniMax-M2.7',
baseURL: 'https://your-custom-endpoint.com',
apiKey: 'your-api-key', // alternatively to using the environment variable
},
},
};
```
</CodeGroup>
## Config
All available parameters for the `minimax` config are present in [Master List of All Params in Config](../config).
+1 -1
View File
@@ -20,7 +20,7 @@ config = {
"llm": {
"provider": "xai",
"config": {
"model": "grok-4.3",
"model": "grok-3-beta",
"temperature": 0.1,
"max_tokens": 2000,
}
+1 -1
View File
@@ -16,7 +16,7 @@ For a comprehensive list of available parameters for llm configuration, please r
See the list of supported LLMs below.
<Note>
All LLMs are supported in Python. The following LLMs are also supported in TypeScript: **OpenAI**, **Anthropic**, **Groq**, **Azure OpenAI**, **DeepSeek**, **Google AI**, **Langchain**, **LM Studio**, **Mistral AI**, and **Ollama**.
All LLMs are supported in Python. The following LLMs are also supported in TypeScript: **OpenAI**, **Anthropic**, and **Groq**.
</Note>
<CardGroup cols={4}>
+1 -1
View File
@@ -198,4 +198,4 @@ for i, prompt in enumerate(prompts):
- **Too Long**: Keep prompts under token limits for your chosen LLM
- **Too Vague**: Be specific about scoring criteria
- **Wrong Scale**: Use 0.0-1.0 scale to match the default score extractor
- **Extra Output**: Ask for only the numeric score: extra text can confuse score extraction
- **Extra Output**: Ask for only the numeric score — extra text can confuse score extraction
+226
View File
@@ -0,0 +1,226 @@
---
title: LLM as Reranker
description: "Use any LLM as a flexible reranker in Mem0 with custom prompts and domain-specific scoring logic."
---
<Warning>
**This page has been superseded.** Please see [LLM Reranker](/components/rerankers/models/llm_reranker) for the complete and up-to-date documentation on using LLMs for reranking.
</Warning>
LLM-based reranker provides maximum flexibility by using any Large Language Model to score document relevance. This approach allows for custom prompts and domain-specific scoring logic.
## Supported LLM Providers
Any LLM provider supported by Mem0 can be used for reranking:
- **OpenAI**: GPT-4, GPT-3.5-turbo, etc.
- **Anthropic**: Claude models
- **Together**: Open-source models
- **Groq**: Fast inference
- **Ollama**: Local models
- And more...
## Configuration
```python Python
from mem0 import Memory
config = {
"vector_store": {
"provider": "chroma",
"config": {
"collection_name": "my_memories",
"path": "./chroma_db"
}
},
"llm": {
"provider": "openai",
"config": {
"model": "gpt-4o-mini"
}
},
"reranker": {
"provider": "llm",
"config": {
"model": "gpt-4o-mini",
"provider": "openai",
"api_key": "your-openai-api-key", # or set OPENAI_API_KEY
"top_k": 5,
"temperature": 0.0
}
}
}
memory = Memory.from_config(config)
```
## Custom Scoring Prompt
You can provide a custom prompt for relevance scoring:
```python Python
custom_prompt = """You are a relevance scoring assistant. Rate how well this document answers the query.
Query: "{query}"
Document: "{document}"
Score from 0.0 to 1.0 where:
- 1.0: Perfect match, directly answers the query
- 0.8-0.9: Highly relevant, good match
- 0.6-0.7: Moderately relevant, partial match
- 0.4-0.5: Slightly relevant, limited useful information
- 0.0-0.3: Not relevant or no useful information
Provide only a single numerical score between 0.0 and 1.0."""
config["reranker"]["config"]["scoring_prompt"] = custom_prompt
```
## Usage Example
```python Python
import os
from mem0 import Memory
# Set API key
os.environ["OPENAI_API_KEY"] = "your-api-key"
# Initialize memory with LLM reranker
config = {
"vector_store": {"provider": "chroma"},
"llm": {"provider": "openai", "config": {"model": "gpt-4o-mini"}},
"reranker": {
"provider": "llm",
"config": {
"model": "gpt-4o-mini",
"provider": "openai",
"temperature": 0.0
}
}
}
memory = Memory.from_config(config)
# Add memories
messages = [
{"role": "user", "content": "I'm learning Python programming"},
{"role": "user", "content": "I find object-oriented programming challenging"},
{"role": "user", "content": "I love hiking in national parks"}
]
memory.add(messages, user_id="david")
# Search with LLM reranking
results = memory.search("What programming topics is the user studying?", filters={"user_id": "david"})
for result in results['results']:
print(f"Memory: {result['memory']}")
print(f"Vector Score: {result['score']:.3f}")
print(f"Rerank Score: {result['rerank_score']:.3f}")
print()
```
```text Output
Memory: I'm learning Python programming
Vector Score: 0.856
Rerank Score: 0.920
Memory: I find object-oriented programming challenging
Vector Score: 0.782
Rerank Score: 0.850
```
## Domain-Specific Scoring
Create specialized scoring for your domain:
```python Python
medical_prompt = """You are a medical relevance expert. Score how relevant this medical record is to the clinical query.
Clinical Query: "{query}"
Medical Record: "{document}"
Consider:
- Clinical relevance and accuracy
- Patient safety implications
- Diagnostic value
- Treatment relevance
Score from 0.0 to 1.0. Provide only the numerical score."""
config = {
"reranker": {
"provider": "llm",
"config": {
"model": "gpt-4o-mini",
"provider": "openai",
"scoring_prompt": medical_prompt,
"temperature": 0.0
}
}
}
```
## Multiple LLM Providers
Use different LLM providers for reranking:
```python Python
# Using Anthropic Claude
anthropic_config = {
"reranker": {
"provider": "llm",
"config": {
"model": "claude-3-haiku-20240307",
"provider": "anthropic",
"temperature": 0.0
}
}
}
# Using local Ollama model
ollama_config = {
"reranker": {
"provider": "llm",
"config": {
"model": "llama2:7b",
"provider": "ollama",
"temperature": 0.0
}
}
}
```
## Configuration Parameters
| Parameter | Description | Type | Default |
|-----------|-------------|------|---------|
| `model` | LLM model to use for scoring | `str` | `"gpt-4o-mini"` |
| `provider` | LLM provider name | `str` | `"openai"` |
| `api_key` | API key for the LLM provider | `str` | `None` |
| `top_k` | Maximum documents to return | `int` | `None` |
| `temperature` | Temperature for LLM generation | `float` | `0.0` |
| `max_tokens` | Maximum tokens for LLM response | `int` | `100` |
| `scoring_prompt` | Custom prompt template | `str` | Default prompt |
## Advantages
- **Maximum Flexibility**: Custom prompts for any use case
- **Domain Expertise**: Leverage LLM knowledge for specialized domains
- **Interpretability**: Understand scoring through prompt engineering
- **Multi-criteria**: Score based on multiple relevance factors
## Considerations
- **Latency**: Higher latency than specialized rerankers
- **Cost**: LLM API costs per reranking operation
- **Consistency**: May have slight variations in scoring
- **Prompt Engineering**: Requires careful prompt design
## Best Practices
1. **Temperature**: Use 0.0 for consistent scoring
2. **Prompt Design**: Be specific about scoring criteria
3. **Token Efficiency**: Keep prompts concise to reduce costs
4. **Caching**: Cache results for repeated queries when possible
5. **Fallback**: Handle API errors gracefully
+1 -1
View File
@@ -100,7 +100,7 @@ To enable Role-Based Access Control (RBAC) for Azure AI Search, follow these ste
1. In the Azure Portal, navigate to your **Azure AI Search** service.
2. In the left menu, select **Settings** > **Keys**.
3. Change the authentication setting to **Role-based access control**, or **Both** if you need API key compatibility. The default is “Key-based authentication”: you must switch it to use Azure roles.
3. Change the authentication setting to **Role-based access control**, or **Both** if you need API key compatibility. The default is “Key-based authentication”—you must switch it to use Azure roles.
4. **Go to Access Control (IAM):**
- In the Azure Portal, select your Search service.
- Click **Access Control (IAM)** on the left.
+1 -1
View File
@@ -46,7 +46,7 @@ Here are the parameters available for configuring Baidu VectorDB:
| `account` | Baidu VectorDB account name | `root` |
| `api_key` | API key for accessing Baidu VectorDB | Required |
| `database_name` | Name of the database | `mem0` |
| `table_name` | Name of the table | `mem0` |
| `table_name` | Name of the table | `mem0_table` |
| `embedding_model_dims` | Dimensions of the embedding model | `1536` |
| `metric_type` | Distance metric for similarity search | `L2` |
@@ -56,8 +56,6 @@ Here are the parameters available for configuring Elasticsearch:
| `api_key` | API key for authentication | `None` |
| `user` | Username for basic authentication | `None` |
| `password` | Password for basic authentication | `None` |
| `use_ssl` | Whether to use SSL for the connection | `True` |
| `ca_certs` | Path to CA bundle for SSL certificate verification | `None` |
| `verify_certs` | Whether to verify SSL certificates | `True` |
| `auto_create_index` | Whether to automatically create the index | `True` |
| `custom_search_query` | Function returning a custom search query | `None` |
-1
View File
@@ -55,7 +55,6 @@ Here are the parameters available for configuring FAISS:
| `path` | Path to store FAISS index and metadata | `/tmp/faiss/<collection_name>` |
| `distance_strategy` | Distance metric strategy to use (options: 'euclidean', 'inner_product', 'cosine') | `euclidean` |
| `normalize_L2` | Whether to normalize L2 vectors (only applicable for euclidean distance) | `False` |
| `embedding_model_dims` | Dimensions of the embedding model | `1536` |
### Performance Considerations
+3 -3
View File
@@ -47,12 +47,12 @@ m.add(messages, user_id="alice", metadata={"category": "movies"})
```
```typescript TypeScript
import { Memory } from "mem0ai/oss";
import { Memory } from "mem0ai";
import { OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { MemoryVectorStore as LangchainMemoryStore } from "langchain/vectorstores/memory";
const embeddings = new OpenAIEmbeddings();
const vectorStore = new MemoryVectorStore(embeddings);
const vectorStore = new LangchainVectorStore(embeddings);
const config = {
"vector_store": {
+3 -3
View File
@@ -42,8 +42,8 @@ Here are the parameters available for configuring MongoDB:
| Parameter | Description | Default Value |
| --- | --- | --- |
| db_name | Name of the MongoDB database | `"mem0_db"` |
| collection_name | Name of the MongoDB collection | `"mem0"` |
| collection_name | Name of the MongoDB collection | `"mem0_collection"` |
| embedding_model_dims | Dimensions of the embedding vectors | `1536` |
| mongo_uri | The MongoDB URI connection string | `mongodb://localhost:27017` |
| mongo_uri | The MongoDB URI connection string | `mongodb://username:password@localhost:27017` |
> **Note**: If `mongo_uri` is not provided, it will default to `mongodb://localhost:27017`.
> **Note**: If `mongo_uri` is not provided, it will default to `mongodb://username:password@localhost:27017`.
-153
View File
@@ -1,153 +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 m = new Memory({
vectorStore: {
provider: "pgvector",
config: {
connectionString: process.env.DATABASE_URL!,
ssl: {
rejectUnauthorized: false,
},
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">
Use the Neon `DATABASE_URL` directly with `connectionString`. Set `ssl` if your runtime needs an explicit TLS config object.
| Parameter | Description | Default |
| -------------------- | ---------------------------------------------- | -------------- |
| `connectionString` | Neon Postgres connection string. | Required |
| `ssl` | Optional TLS settings passed directly to `pg`. | Driver default |
| `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` |
**TLS note:** `ssl: true` is sufficient for most Neon connections since Neon uses valid certificates. Use `ssl: { rejectUnauthorized: false }` only when connecting through Neon's connection pooler on certain edge runtimes (e.g. Cloudflare Workers) that require it, or when your environment does not trust the Neon CA chain.
</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`

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