Compare commits

...
Author SHA1 Message Date
KartikandGitHub b3ede5b7c0 chore: update changelog, bump SDK and package versions to 3.0.8 and 2.0.6 (#5522) 2026-06-13 20:59:53 +05:30
youneshimaandGitHub 3553fc79dd feat(memory): add OSS-to-Platform notices (#5494) 2026-06-13 18:34:20 +05:30
KartikandGitHub f322cf82b9 chore: consolidate cookbooks/ into an indexed examples/ directory (#5517) 2026-06-13 18:25:50 +05:30
KartikandGitHub 73c975ba68 chore: bump version to 0.1.3, update mem0ai to ^3.0.7, and adjust CHANGELOG (#5521) 2026-06-13 18:10:50 +05:30
KartikandGitHub 931d579ba5 chore(openclaw): release v1.0.13 and backfill v1.0.12 changelog (#5519) 2026-06-13 17:59:04 +05:30
KartikandGitHub f4773a0baf fix(mem0-plugin): accurate per-editor telemetry attribution + OpenCode telemetry (#5518) 2026-06-13 16:48:29 +05:30
KartikandGitHub 06d33f6cc4 fix: relax flaky entity boost parallelism timing threshold (#5511) 2026-06-12 21:07:47 +05:30
Hrushikesh YadavandGitHub 8f3b60f3e1 fix: prevent crash in parse_vision_messages when vision is disabled (#5487) 2026-06-12 20:41:18 +05:30
Harsh Vardhan GuptaandGitHub a6e27dcc9c fix(@mem0/community): upgrade @langchain/community to ^1.1.18 (CVE-2026-27795, CVE-2026-26019) (#5510) 2026-06-12 20:07:03 +05:30
Yufeng HeandGitHub 4f10c986b5 fix: expose Qdrant https option (#5380) 2026-06-12 20:06:26 +05:30
821152bd14 Fix OpenClaw Mem0 custom categories payload (#5345)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-12 19:48:53 +05:30
f48b133101 feat(skills): add mem0-oss-to-platform migration skill (#5455)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: kartik-mem0 <kartik.labhshetwar@mem0.ai>
2026-06-12 19:48:37 +05:30
1d56f85705 fix(cli): resolve Windows environment compatibility issues in python CLI tests (#5464)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-12 19:40:26 +05:30
Hrushikesh YadavandGitHub ced852033b fix: return 400 instead of 502 for invalid search filters (#5482) 2026-06-12 19:35:24 +05:30
Yufeng HeandGitHub b9ad8fa8b2 fix(openclaw): skip runtime setup during metadata registration (#5383) 2026-06-12 19:32:59 +05:30
e3f5ce7b41 fix: use valid S3 entity index names (#5416)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-12 19:22:32 +05:30
KartikandGitHub f681889b14 fix(pi-agent-plugin): make command results visible and relevance-filtered (#5504) 2026-06-12 19:13:31 +05:30
KartikandGitHub b5ec46be5b fix(plugin): guard bare $USER refs in on_session_start.sh for Windows (#5492) 2026-06-12 19:13:19 +05:30
168ad358d5 fix(deps): resolve all open MEDIUM Dependabot alerts (npm overrides + Python pins) (#5489)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:15:26 +05:30
2c796d144f refactor: consolidate agent/editor plugins under integrations/ (#5491)
Co-authored-by: Claude <noreply@anthropic.com>
2026-06-12 10:31:35 +05:30
c676c2c458 fix(dashboard): pin pnpm to 10.34.2 so docker build works on node:20-alpine (#5483)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-11 22:45:52 +05:30
b36847622d fix(langchain): search() crashes with TypeError when score is None (#5072)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-11 22:34:06 +05:30
Hrushikesh YadavandGitHub 32c8849044 fix: remove dead _process_config method in Memory and AsyncMemory (#5486) 2026-06-11 22:26:53 +05:30
Hrushikesh YadavandGitHub 2dd2872c08 fix: use 'is not None' instead of truthiness for vector/payload in pgvector update (#5488) 2026-06-11 22:12:38 +05:30
cf268da19d fix(demo): guard against undefined data in useMemories hook (v2 async response) (#5029)
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
2026-06-11 21:50:35 +05:30
Sense_wangandGitHub 7a5df64746 fix: allow dashboard refresh cookie on http deployments (#5026) 2026-06-11 21:29:54 +05:30
4c41f6deeb fix(vector-stores): index Valkey 'memory' field as TEXT not TAG (#5443)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: kartik-mem0 <kartik.labhshetwar@mem0.ai>
2026-06-11 21:28:42 +05:30
Hrushikesh YadavandGitHub f84aa1eb31 fix: implement $not filter support in ChromaDB vector store (#5485) 2026-06-11 20:12:39 +05:30
Saket AryanandGitHub 9226ee2229 ci: aggregate all PR testing behind a single required CI Gate workflow (#5476) 2026-06-11 15:24:51 +05:30
KartikandGitHub 8399b088a5 chore: release Python SDK v2.0.5 and TypeScript SDK v3.0.7 (#5470) 2026-06-10 22:17:16 +05:30
Saket AryanandGitHub 437f0b5495 ci: route all release publishing through a single Release Router workflow (#5475) 2026-06-10 22:16:58 +05:30
398 changed files with 16565 additions and 5028 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
"name": "mem0", "name": "mem0",
"source": { "source": {
"source": "local", "source": "local",
"path": "./mem0-plugin" "path": "./integrations/mem0-plugin"
}, },
"policy": { "policy": {
"installation": "AVAILABLE", "installation": "AVAILABLE",
+2 -2
View File
@@ -10,9 +10,9 @@
"plugins": [ "plugins": [
{ {
"name": "mem0", "name": "mem0",
"source": "./mem0-plugin", "source": "./integrations/mem0-plugin",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.", "description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
"version": "0.2.9" "version": "0.2.10"
} }
] ]
} }
+1 -1
View File
@@ -8,7 +8,7 @@
"name": "mem0", "name": "mem0",
"source": { "source": {
"source": "local", "source": "local",
"path": "./mem0-plugin" "path": "./integrations/mem0-plugin"
}, },
"policy": { "policy": {
"installation": "AVAILABLE", "installation": "AVAILABLE",
+2 -2
View File
@@ -10,9 +10,9 @@
"plugins": [ "plugins": [
{ {
"name": "mem0", "name": "mem0",
"source": "./mem0-plugin", "source": "./integrations/mem0-plugin",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search.", "description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search.",
"version": "0.2.9" "version": "0.2.10"
} }
] ]
} }
+16 -4
View File
@@ -1,20 +1,33 @@
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
# Pure SDK version tags only (v1.2.3) — excludes package-prefixed tags # Pure SDK version tags only (v1.2.3) — excludes package-prefixed tags
# like vercel-ai-v* that also start with 'v' # like vercel-ai-v* that also start with 'v'
if: startsWith(github.event.release.tag_name, 'v') && !contains(github.event.release.tag_name, '-v') if: startsWith(inputs.tag, 'v') && !contains(inputs.tag, '-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with:
ref: ${{ inputs.tag }}
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v2 uses: actions/setup-python@v2
@@ -41,7 +54,6 @@ jobs:
# packages_dir: dist/ # packages_dir: dist/
- name: Publish distribution 📦 to PyPI - name: Publish distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-v')
uses: pypa/gh-action-pypi-publish@release/v1 uses: pypa/gh-action-pypi-publish@release/v1
with: with:
packages_dir: dist/ packages_dir: dist/
+171
View File
@@ -0,0 +1,171 @@
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."
+3 -1
View File
@@ -1,9 +1,11 @@
name: ci name: ci
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main runs remain standalone.
on: on:
push: push:
branches: [main] branches: [main]
pull_request: workflow_call:
jobs: jobs:
changelog_check: changelog_check:
+18 -4
View File
@@ -1,13 +1,25 @@
name: Publish @mem0/cli 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish @mem0/cli 📦 to npm name: Build and publish @mem0/cli 📦 to npm
if: startsWith(github.event.release.tag_name, 'cli-node-v') if: startsWith(inputs.tag, 'cli-node-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
@@ -16,6 +28,8 @@ jobs:
working-directory: cli/node working-directory: cli/node
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
@@ -38,7 +52,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+3 -4
View File
@@ -1,5 +1,7 @@
name: CLI Node CI 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: on:
workflow_dispatch: workflow_dispatch:
push: push:
@@ -7,10 +9,7 @@ on:
paths: paths:
- 'cli/node/**' - 'cli/node/**'
- '.github/workflows/cli-node-ci.yml' - '.github/workflows/cli-node-ci.yml'
pull_request: workflow_call:
paths:
- 'cli/node/**'
- '.github/workflows/cli-node-ci.yml'
jobs: jobs:
lint: lint:
+16 -3
View File
@@ -1,13 +1,24 @@
name: Publish mem0-cli 🐍 distributions 📦 to PyPI 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish mem0-cli 📦 to PyPI name: Build and publish mem0-cli 📦 to PyPI
if: startsWith(github.event.release.tag_name, 'cli-v') if: startsWith(inputs.tag, 'cli-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
@@ -16,6 +27,8 @@ jobs:
working-directory: cli/python working-directory: cli/python
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5
+3 -4
View File
@@ -1,5 +1,7 @@
name: CLI Python CI 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: on:
workflow_dispatch: workflow_dispatch:
push: push:
@@ -7,10 +9,7 @@ on:
paths: paths:
- 'cli/python/**' - 'cli/python/**'
- '.github/workflows/cli-python-ci.yml' - '.github/workflows/cli-python-ci.yml'
pull_request: workflow_call:
paths:
- 'cli/python/**'
- '.github/workflows/cli-python-ci.yml'
jobs: jobs:
lint: lint:
+3 -6
View File
@@ -6,13 +6,10 @@ name: docs - llms.txt check
# python scripts/check-llms-txt-coverage.py # read-only # python scripts/check-llms-txt-coverage.py # read-only
# python scripts/check-llms-txt-coverage.py --write # scaffold placeholders # 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: on:
pull_request: workflow_call:
paths:
- 'docs/**/*.mdx'
- 'docs/llms.txt'
- 'scripts/check-llms-txt-coverage.py'
- 'scripts/llms-txt-ignore.txt'
workflow_dispatch: {} workflow_dispatch: {}
permissions: permissions:
+20 -6
View File
@@ -1,21 +1,35 @@
name: Publish @mem0/openclaw-mem0 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish @mem0/openclaw-mem0 📦 to npm name: Build and publish @mem0/openclaw-mem0 📦 to npm
if: startsWith(github.event.release.tag_name, 'openclaw-v') if: startsWith(inputs.tag, 'openclaw-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
defaults: defaults:
run: run:
working-directory: openclaw working-directory: integrations/openclaw
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
@@ -28,7 +42,7 @@ jobs:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: openclaw/pnpm-lock.yaml cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -38,7 +52,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+16 -17
View File
@@ -1,16 +1,15 @@
name: openclaw checks 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: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [main] branches: [main]
paths: paths:
- 'openclaw/**' - 'integrations/openclaw/**'
- '.github/workflows/openclaw-checks.yml'
pull_request:
paths:
- 'openclaw/**'
- '.github/workflows/openclaw-checks.yml' - '.github/workflows/openclaw-checks.yml'
workflow_call:
jobs: jobs:
lint: lint:
@@ -28,13 +27,13 @@ jobs:
with: with:
node-version: 20 node-version: 20
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: openclaw/pnpm-lock.yaml cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd openclaw && pnpm install --frozen-lockfile run: cd integrations/openclaw && pnpm install --frozen-lockfile
- name: Type check - name: Type check
run: cd openclaw && pnpm exec tsc --noEmit run: cd integrations/openclaw && pnpm exec tsc --noEmit
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -54,20 +53,20 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: openclaw/pnpm-lock.yaml cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd openclaw && pnpm install --frozen-lockfile run: cd integrations/openclaw && pnpm install --frozen-lockfile
- name: Run tests with coverage - name: Run tests with coverage
run: cd openclaw && pnpm exec vitest run --coverage run: cd integrations/openclaw && pnpm exec vitest run --coverage
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
if: matrix.node-version == 20 if: matrix.node-version == 20
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v4
with: with:
flags: openclaw flags: openclaw
directory: openclaw/coverage directory: integrations/openclaw/coverage
env: env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -86,15 +85,15 @@ jobs:
with: with:
node-version: 20 node-version: 20
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: openclaw/pnpm-lock.yaml cache-dependency-path: integrations/openclaw/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd openclaw && pnpm install --frozen-lockfile run: cd integrations/openclaw && pnpm install --frozen-lockfile
- name: Build - name: Build
run: cd openclaw && pnpm build run: cd integrations/openclaw && pnpm build
- name: Verify dist output exists - name: Verify dist output exists
run: | run: |
test -f openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1) test -f integrations/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) test -f integrations/openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
+19 -5
View File
@@ -1,21 +1,35 @@
name: Publish @mem0/opencode-plugin 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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: jobs:
build-n-publish: build-n-publish:
name: Build and publish @mem0/opencode-plugin 📦 to npm name: Build and publish @mem0/opencode-plugin 📦 to npm
if: startsWith(github.event.release.tag_name, 'opencode-v') if: startsWith(inputs.tag, 'opencode-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
defaults: defaults:
run: run:
working-directory: mem0-plugin/.opencode-plugin working-directory: integrations/mem0-plugin/.opencode-plugin
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install Bun - name: Install Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
@@ -36,7 +50,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+5 -6
View File
@@ -1,23 +1,22 @@
name: opencode-plugin checks 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: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [main] branches: [main]
paths: paths:
- 'mem0-plugin/.opencode-plugin/**' - 'integrations/mem0-plugin/.opencode-plugin/**'
- '.github/workflows/opencode-plugin-checks.yml'
pull_request:
paths:
- 'mem0-plugin/.opencode-plugin/**'
- '.github/workflows/opencode-plugin-checks.yml' - '.github/workflows/opencode-plugin-checks.yml'
workflow_call:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
defaults: defaults:
run: run:
working-directory: mem0-plugin/.opencode-plugin working-directory: integrations/mem0-plugin/.opencode-plugin
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
+20 -6
View File
@@ -1,21 +1,35 @@
name: Publish @mem0/pi-agent-plugin 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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: jobs:
build-n-publish: build-n-publish:
name: Build and publish @mem0/pi-agent-plugin 📦 to npm name: Build and publish @mem0/pi-agent-plugin 📦 to npm
if: startsWith(github.event.release.tag_name, 'pi-agent-v') if: startsWith(inputs.tag, 'pi-agent-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
defaults: defaults:
run: run:
working-directory: pi-agent-plugin working-directory: integrations/pi-agent-plugin
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
@@ -28,7 +42,7 @@ jobs:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: pi-agent-plugin/pnpm-lock.yaml cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -38,7 +52,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+17 -18
View File
@@ -1,16 +1,15 @@
name: pi-agent-plugin checks 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: on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: [main] branches: [main]
paths: paths:
- 'pi-agent-plugin/**' - 'integrations/pi-agent-plugin/**'
- '.github/workflows/pi-agent-plugin-checks.yml'
pull_request:
paths:
- 'pi-agent-plugin/**'
- '.github/workflows/pi-agent-plugin-checks.yml' - '.github/workflows/pi-agent-plugin-checks.yml'
workflow_call:
jobs: jobs:
lint: lint:
@@ -28,13 +27,13 @@ jobs:
with: with:
node-version: 20 node-version: 20
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: pi-agent-plugin/pnpm-lock.yaml cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd pi-agent-plugin && pnpm install --frozen-lockfile run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Type check - name: Type check
run: cd pi-agent-plugin && pnpm exec tsc --noEmit run: cd integrations/pi-agent-plugin && pnpm exec tsc --noEmit
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -54,13 +53,13 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: pi-agent-plugin/pnpm-lock.yaml cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd pi-agent-plugin && pnpm install --frozen-lockfile run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Run tests - name: Run tests
run: cd pi-agent-plugin && pnpm exec vitest run run: cd integrations/pi-agent-plugin && pnpm exec vitest run
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -77,17 +76,17 @@ jobs:
with: with:
node-version: 20 node-version: 20
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: pi-agent-plugin/pnpm-lock.yaml cache-dependency-path: integrations/pi-agent-plugin/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: cd pi-agent-plugin && pnpm install --frozen-lockfile run: cd integrations/pi-agent-plugin && pnpm install --frozen-lockfile
- name: Build - name: Build
run: cd pi-agent-plugin && pnpm build run: cd integrations/pi-agent-plugin && pnpm build
- name: Verify dist output exists - name: Verify dist output exists
run: | run: |
test -f pi-agent-plugin/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1) test -f integrations/pi-agent-plugin/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
test -f pi-agent-plugin/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1) test -f integrations/pi-agent-plugin/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
test -f pi-agent-plugin/dist/entry.js || (echo "Build output missing: dist/entry.js" && exit 1) test -f integrations/pi-agent-plugin/dist/entry.js || (echo "Build output missing: dist/entry.js" && exit 1)
test -f pi-agent-plugin/dist/entry.d.ts || (echo "Build output missing: dist/entry.d.ts" && 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
@@ -0,0 +1,68 @@
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 }}"
+17 -4
View File
@@ -1,13 +1,24 @@
name: Publish mem0ai 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish mem0ai 📦 to npm name: Build and publish mem0ai 📦 to npm
if: startsWith(github.event.release.tag_name, 'ts-v') if: startsWith(inputs.tag, 'ts-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
@@ -16,6 +27,8 @@ jobs:
working-directory: mem0-ts working-directory: mem0-ts
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
@@ -38,7 +51,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+3 -3
View File
@@ -1,14 +1,14 @@
name: TypeScript SDK CI name: TypeScript SDK CI
# On PRs this is invoked by ci-gate.yml (the single required check);
# push-to-main runs remain standalone.
on: on:
push: push:
branches: [main] branches: [main]
paths: paths:
- 'mem0-ts/**' - 'mem0-ts/**'
- '.github/workflows/ts-sdk-ci.yml' - '.github/workflows/ts-sdk-ci.yml'
pull_request: workflow_call:
paths:
- 'mem0-ts/**'
jobs: jobs:
check_changes: check_changes:
+20 -6
View File
@@ -1,21 +1,35 @@
name: Publish @mem0/vercel-ai-provider 📦 to npm 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: on:
release: workflow_dispatch:
types: [published] 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
jobs: jobs:
build-n-publish: build-n-publish:
name: Build and publish @mem0/vercel-ai-provider 📦 to npm name: Build and publish @mem0/vercel-ai-provider 📦 to npm
if: startsWith(github.event.release.tag_name, 'vercel-ai-v') if: startsWith(inputs.tag, 'vercel-ai-v')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
defaults: defaults:
run: run:
working-directory: vercel-ai-sdk working-directory: integrations/vercel-ai-sdk
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
@@ -28,7 +42,7 @@ jobs:
node-version: '22' node-version: '22'
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: vercel-ai-sdk/pnpm-lock.yaml cache-dependency-path: integrations/vercel-ai-sdk/pnpm-lock.yaml
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -38,7 +52,7 @@ jobs:
- name: Publish to npm - name: Publish to npm
run: | run: |
if [ "${{ github.event.release.prerelease }}" = "true" ]; then if [ "${{ inputs.prerelease }}" = "true" ]; then
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]") PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
npx npm@latest publish --provenance --access public --tag "$PREID" npx npm@latest publish --provenance --access public --tag "$PREID"
else else
+52 -28
View File
@@ -22,17 +22,18 @@ This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs,
| `mem0-ts/` | TypeScript SDK (`mem0ai` on npm) — client + OSS memory | | `mem0-ts/` | TypeScript SDK (`mem0ai` on npm) — client + OSS memory |
| `cli/python/` | Python CLI (`mem0-cli` on PyPI) — Typer-based, entry point `mem0` | | `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` | | `cli/node/` | Node CLI (`@mem0/cli` on npm) — Commander-based, entry point `mem0` |
| `vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider | | `integrations/` | **Agent & editor integrations**, one directory per integration (see "Adding a New Integration") |
| `openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors | | `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 |
| `server/` | FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + PostgreSQL/pgvector + Neo4j) | | `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) | | `openmemory/` | Self-hosted memory platform — `api/` (FastAPI + Alembic + MCP server) and `ui/` (Next.js 15 + React 19) |
| `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/`, `mem0-oss-to-platform/` |
| `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) | | `docs/` | Documentation site (Mintlify) |
| `tests/` | Python SDK tests (pytest) | | `tests/` | Python SDK tests (pytest) |
| `evaluation/` | Benchmarking framework — LOCOMO evals, experiment runner, score generation | | `evaluation/` | Benchmarking framework — LOCOMO evals, experiment runner, score generation |
| `examples/` | Sample projects — demo apps, Chrome extension, multi-agent patterns | | `examples/` | Sample projects & runnable demos — apps, Chrome extension, multi-agent patterns, and Jupyter notebooks (`notebooks/`) |
| `cookbooks/` | Jupyter notebooks — customer support chatbot, AutoGen integration |
| `pr-reviews/` | Pull request review materials | | `pr-reviews/` | Pull request review materials |
| `scripts/` | Repo-wide utility scripts (e.g., `check-llms-txt-coverage.py` for docs/llms.txt sync) | | `scripts/` | Repo-wide utility scripts (e.g., `check-llms-txt-coverage.py` for docs/llms.txt sync) |
@@ -49,8 +50,8 @@ mem0 (Python SDK) mem0-ts (TypeScript SDK)
cli/python/ ──▶ mem0ai (optional, for OSS mode) cli/python/ ──▶ mem0ai (optional, for OSS mode)
cli/node/ ──▶ mem0ai (npm, for API calls) cli/node/ ──▶ mem0ai (npm, for API calls)
vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers integrations/vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
openclaw/ ──▶ mem0ai (npm) integrations/openclaw/ ──▶ mem0ai (npm)
``` ```
## Development Setup ## Development Setup
@@ -73,8 +74,8 @@ pre-commit install # install git hooks
# TypeScript packages # TypeScript packages
cd mem0-ts && pnpm install # TS SDK cd mem0-ts && pnpm install # TS SDK
cd cli/node && pnpm install # Node CLI cd cli/node && pnpm install # Node CLI
cd vercel-ai-sdk && pnpm install # Vercel AI provider cd integrations/vercel-ai-sdk && pnpm install # Vercel AI provider
cd openclaw && pnpm install # OpenClaw plugin cd integrations/openclaw && pnpm install # OpenClaw plugin
``` ```
## Build, Lint, and Test Commands ## Build, Lint, and Test Commands
@@ -162,10 +163,10 @@ pnpm run dev # tsx src/index.ts (development)
- **Test:** vitest (not jest) - **Test:** vitest (not jest)
- **Framework:** Commander + Chalk + ora + cli-table3 - **Framework:** Commander + Chalk + ora + cli-table3
### Vercel AI SDK Provider (`vercel-ai-sdk/`) ### Vercel AI SDK Provider (`integrations/vercel-ai-sdk/`)
```bash ```bash
cd vercel-ai-sdk cd integrations/vercel-ai-sdk
pnpm install pnpm install
pnpm run build # tsup pnpm run build # tsup
pnpm run lint # eslint pnpm run lint # eslint
@@ -180,10 +181,10 @@ pnpm run test:node # vitest (node runtime)
- **Lint:** ESLint + Prettier - **Lint:** ESLint + Prettier
- **Test:** jest + vitest (edge/node configs) - **Test:** jest + vitest (edge/node configs)
### OpenClaw Plugin (`openclaw/`) ### OpenClaw Plugin (`integrations/openclaw/`)
```bash ```bash
cd openclaw cd integrations/openclaw
pnpm install pnpm install
pnpm run build # tsup pnpm run build # tsup
pnpm run test # vitest run pnpm run test # vitest run
@@ -342,8 +343,8 @@ make run-openai # OpenAI comparison
|---------|--------|-----------|---------------| |---------|--------|-----------|---------------|
| `mem0-ts/` | — | Prettier | jest | | `mem0-ts/` | — | Prettier | jest |
| `cli/node/` | Biome | Biome | vitest | | `cli/node/` | Biome | Biome | vitest |
| `vercel-ai-sdk/` | ESLint | Prettier | jest + vitest | | `integrations/vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
| `openclaw/` | — | — | vitest | | `integrations/openclaw/` | — | — | vitest |
### Type Checking ### Type Checking
@@ -381,14 +382,14 @@ Model Context Protocol support in multiple places:
- **Remote:** MCP server at `mcp.mem0.ai` - **Remote:** MCP server at `mcp.mem0.ai`
- **Local:** MCP server in `openmemory/api/` (FastAPI-based) - **Local:** MCP server in `openmemory/api/` (FastAPI-based)
- **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:** 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 & Skills System ### Plugin & Skills System
- `mem0-plugin/` provides integrations for Claude Code, Cursor, and Codex via MCP server connections and lifecycle hooks for automatic memory capture. - `integrations/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: - `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). - **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. - **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).
### Adding a New Provider ### Adding a New Provider
@@ -402,24 +403,44 @@ 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`) 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 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/CD
### CI Workflows (automated testing) ### CI Workflows (automated testing)
| Workflow | File | Triggers | Tests | 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.
|----------|------|----------|-------|
| Python SDK | `ci.yml` | Push to main, PRs on `mem0/`, `tests/`, `pyproject.toml` | Ruff lint + pytest on Python 3.10, 3.11, 3.12 | | Workflow | File | Standalone Triggers | Tests |
| 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 | | CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates the workflows below |
| Node CLI | `cli-node-ci.yml` | Push to `cli/node/`, PRs, manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 | | Python SDK | `ci.yml` | Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
| OpenClaw | `openclaw-checks.yml` | Push to `openclaw/`, PRs, manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 | | TypeScript SDK | `ts-sdk-ci.yml` | Push to main (on `mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to `mem0-plugin/.opencode-plugin/`, PRs, manual | Bun: tsc type-check + build + dist artifact check | | 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 |
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to `pi-agent-plugin/`, PRs, manual | tsc + vitest + tsup build (dist artifact check) on Node 20, 22 | | 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.
### CD Workflows (automated publishing) ### 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 | | Workflow | File | Tag Prefix | Target |
|----------|------|------------|--------| |----------|------|------------|--------|
| Release Router | `release.yml` | (all releases) | dispatches the matching workflow below |
| Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) | | Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) |
| TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) | | TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) |
| Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) | | Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) |
@@ -429,8 +450,11 @@ To add a new LLM, embedding, vector store, or reranker provider:
| OpenCode Plugin | `opencode-plugin-cd.yml` | `opencode-v*` | npm (`@mem0/opencode-plugin`) | | 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`) | | 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. - 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. - 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 ### Utility Workflows
+2 -1
View File
@@ -1026,7 +1026,8 @@ def get_user_preferences(user_id: str):
### AutoGen Integration ### AutoGen Integration
```python ```python
from cookbooks.helper.mem0_teachability import Mem0Teachability # Mem0Teachability lives in examples/notebooks/helper/ — see examples/notebooks/mem0-autogen.ipynb
from helper.mem0_teachability import Mem0Teachability
from mem0 import Memory from mem0 import Memory
# Add memory capability to AutoGen agents # Add memory capability to AutoGen agents
+2 -1
View File
@@ -186,9 +186,10 @@ npx skills add https://github.com/mem0ai/mem0 --skill mem0-vercel-ai-sdk
```bash ```bash
npx skills add https://github.com/mem0ai/mem0 --skill mem0-integrate 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-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. 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. 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.
### Basic Usage ### Basic Usage
+17 -16
View File
@@ -9,6 +9,7 @@ overrides:
langsmith@<0.6.0: ^0.6.0 langsmith@<0.6.0: ^0.6.0
tar-fs@>=2.0.0 <2.1.4: ^2.1.4 tar-fs@>=2.0.0 <2.1.4: ^2.1.4
picomatch@<2.3.2: ^2.3.2 picomatch@<2.3.2: ^2.3.2
postcss@<8.5.10: '>=8.5.10'
importers: importers:
@@ -38,7 +39,7 @@ importers:
version: 20.19.37 version: 20.19.37
tsup: tsup:
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.5.1(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3) version: 8.5.1(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3)
tsx: tsx:
specifier: ^4.7.0 specifier: ^4.7.0
version: 4.21.0 version: 4.21.0
@@ -829,8 +830,8 @@ packages:
mz@2.7.0: mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
nanoid@3.3.11: nanoid@3.3.12:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
@@ -871,7 +872,7 @@ packages:
engines: {node: '>= 18'} engines: {node: '>= 18'}
peerDependencies: peerDependencies:
jiti: '>=1.21.0' jiti: '>=1.21.0'
postcss: '>=8.0.9' postcss: '>=8.5.10'
tsx: ^4.8.1 tsx: ^4.8.1
yaml: ^2.4.2 yaml: ^2.4.2
peerDependenciesMeta: peerDependenciesMeta:
@@ -884,8 +885,8 @@ packages:
yaml: yaml:
optional: true optional: true
postcss@8.5.8: postcss@8.5.15:
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
readdirp@4.1.2: readdirp@4.1.2:
@@ -997,7 +998,7 @@ packages:
peerDependencies: peerDependencies:
'@microsoft/api-extractor': ^7.36.0 '@microsoft/api-extractor': ^7.36.0
'@swc/core': ^1 '@swc/core': ^1
postcss: ^8.4.12 postcss: '>=8.5.10'
typescript: '>=4.5.0' typescript: '>=4.5.0'
peerDependenciesMeta: peerDependenciesMeta:
'@microsoft/api-extractor': '@microsoft/api-extractor':
@@ -1671,7 +1672,7 @@ snapshots:
object-assign: 4.1.1 object-assign: 4.1.1
thenify-all: 1.6.0 thenify-all: 1.6.0
nanoid@3.3.11: {} nanoid@3.3.12: {}
object-assign@4.1.1: {} object-assign@4.1.1: {}
@@ -1707,16 +1708,16 @@ snapshots:
mlly: 1.8.2 mlly: 1.8.2
pathe: 2.0.3 pathe: 2.0.3
postcss-load-config@6.0.1(postcss@8.5.8)(tsx@4.21.0): postcss-load-config@6.0.1(postcss@8.5.15)(tsx@4.21.0):
dependencies: dependencies:
lilconfig: 3.1.3 lilconfig: 3.1.3
optionalDependencies: optionalDependencies:
postcss: 8.5.8 postcss: 8.5.15
tsx: 4.21.0 tsx: 4.21.0
postcss@8.5.8: postcss@8.5.15:
dependencies: dependencies:
nanoid: 3.3.11 nanoid: 3.3.12
picocolors: 1.1.1 picocolors: 1.1.1
source-map-js: 1.2.1 source-map-js: 1.2.1
@@ -1837,7 +1838,7 @@ snapshots:
ts-interface-checker@0.1.13: {} ts-interface-checker@0.1.13: {}
tsup@8.5.1(postcss@8.5.8)(tsx@4.21.0)(typescript@5.9.3): tsup@8.5.1(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3):
dependencies: dependencies:
bundle-require: 5.1.0(esbuild@0.27.4) bundle-require: 5.1.0(esbuild@0.27.4)
cac: 6.7.14 cac: 6.7.14
@@ -1848,7 +1849,7 @@ snapshots:
fix-dts-default-cjs-exports: 1.0.1 fix-dts-default-cjs-exports: 1.0.1
joycon: 3.1.1 joycon: 3.1.1
picocolors: 1.1.1 picocolors: 1.1.1
postcss-load-config: 6.0.1(postcss@8.5.8)(tsx@4.21.0) postcss-load-config: 6.0.1(postcss@8.5.15)(tsx@4.21.0)
resolve-from: 5.0.0 resolve-from: 5.0.0
rollup: 4.60.0 rollup: 4.60.0
source-map: 0.7.6 source-map: 0.7.6
@@ -1857,7 +1858,7 @@ snapshots:
tinyglobby: 0.2.15 tinyglobby: 0.2.15
tree-kill: 1.2.2 tree-kill: 1.2.2
optionalDependencies: optionalDependencies:
postcss: 8.5.8 postcss: 8.5.15
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- jiti - jiti
@@ -1885,7 +1886,7 @@ snapshots:
esbuild: 0.25.12 esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.4) fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4 picomatch: 4.0.4
postcss: 8.5.8 postcss: 8.5.15
rollup: 4.60.0 rollup: 4.60.0
tinyglobby: 0.2.15 tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
+1
View File
@@ -10,3 +10,4 @@ overrides:
langsmith@<0.6.0: ^0.6.0 langsmith@<0.6.0: ^0.6.0
tar-fs@>=2.0.0 <2.1.4: ^2.1.4 tar-fs@>=2.0.0 <2.1.4: ^2.1.4
picomatch@<2.3.2: ^2.3.2 picomatch@<2.3.2: ^2.3.2
"postcss@<8.5.10": ">=8.5.10"
+6
View File
@@ -8,4 +8,10 @@ export default defineConfig({
define: { define: {
__CLI_VERSION__: JSON.stringify(pkg.version), __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,
},
}); });
+6 -3
View File
@@ -32,12 +32,13 @@ def _run(args: list[str], home_dir: str | None = None) -> subprocess.CompletedPr
if key.startswith("MEM0_"): if key.startswith("MEM0_"):
del env[key] del env[key]
env.pop("FORCE_COLOR", None) env.pop("FORCE_COLOR", None)
env["PYTHONIOENCODING"] = "utf-8"
if home_dir: if home_dir:
env["HOME"] = home_dir env["HOME"] = home_dir
result = subprocess.run( result = subprocess.run(
[sys.executable, "-m", "mem0_cli", *args], [sys.executable, "-m", "mem0_cli", *args],
capture_output=True, capture_output=True,
text=True, encoding="utf-8",
env=env, env=env,
timeout=15, timeout=15,
) )
@@ -99,12 +100,13 @@ class TestArgvPreprocessing:
result = subprocess.run( result = subprocess.run(
[sys.executable, "-m", "mem0_cli", "init", "--agent"], [sys.executable, "-m", "mem0_cli", "init", "--agent"],
capture_output=True, capture_output=True,
text=True, encoding="utf-8",
env={ env={
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")}, **{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
"HOME": clean_home, "HOME": clean_home,
"MEM0_BASE_URL": "http://127.0.0.1:1", # blackhole "MEM0_BASE_URL": "http://127.0.0.1:1", # blackhole
"FORCE_COLOR": "0", "FORCE_COLOR": "0",
"PYTHONIOENCODING": "utf-8",
}, },
timeout=15, timeout=15,
) )
@@ -133,12 +135,13 @@ class TestJsonEnvelopeParity:
result = subprocess.run( result = subprocess.run(
[sys.executable, "-m", "mem0_cli", "init", "--agent", "--json"], [sys.executable, "-m", "mem0_cli", "init", "--agent", "--json"],
capture_output=True, capture_output=True,
text=True, encoding="utf-8",
env={ env={
**{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")}, **{k: v for k, v in os.environ.items() if not k.startswith("MEM0_")},
"HOME": clean_home, "HOME": clean_home,
"MEM0_BASE_URL": "http://127.0.0.1:1", "MEM0_BASE_URL": "http://127.0.0.1:1",
"FORCE_COLOR": "0", "FORCE_COLOR": "0",
"PYTHONIOENCODING": "utf-8",
}, },
timeout=15, timeout=15,
) )
+2 -1
View File
@@ -49,6 +49,7 @@ def _run(
if key.startswith("MEM0_"): if key.startswith("MEM0_"):
del env[key] del env[key]
env.pop("FORCE_COLOR", None) env.pop("FORCE_COLOR", None)
env["PYTHONIOENCODING"] = "utf-8"
if home_dir: if home_dir:
env["HOME"] = home_dir env["HOME"] = home_dir
if env_override: if env_override:
@@ -56,7 +57,7 @@ def _run(
result = subprocess.run( result = subprocess.run(
[sys.executable, "-m", "mem0_cli", *args], [sys.executable, "-m", "mem0_cli", *args],
capture_output=True, capture_output=True,
text=True, encoding="utf-8",
env=env, env=env,
) )
return subprocess.CompletedProcess( return subprocess.CompletedProcess(
+7 -7
View File
@@ -8,8 +8,8 @@ from io import StringIO
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from click.exceptions import Exit as ClickExit
from rich.console import Console from rich.console import Console
from typer import Exit as TyperExit
from mem0_cli.commands.config_cmd import ( from mem0_cli.commands.config_cmd import (
cmd_config_get, cmd_config_get,
@@ -181,7 +181,7 @@ class TestAddCommand:
patch("mem0_cli.commands.memory.console", console), patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console), patch("mem0_cli.commands.memory.err_console", err_console),
patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False), patch("mem0_cli.commands.memory._stdin_is_piped", return_value=False),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_add( cmd_add(
mock_backend, mock_backend,
@@ -206,7 +206,7 @@ class TestAddCommand:
with ( with (
patch("mem0_cli.commands.memory.console", console), patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console), patch("mem0_cli.commands.memory.err_console", err_console),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_add( cmd_add(
mock_backend, mock_backend,
@@ -764,7 +764,7 @@ class TestImportCommand:
with ( with (
patch("mem0_cli.commands.utils.console", console), patch("mem0_cli.commands.utils.console", console),
patch("mem0_cli.commands.utils.err_console", err_console), patch("mem0_cli.commands.utils.err_console", err_console),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None) cmd_import(mock_backend, "/nonexistent/file.json", user_id=None, agent_id=None)
@@ -801,7 +801,7 @@ class TestEntitiesListCommand:
with ( with (
patch("mem0_cli.commands.entities.console", console), patch("mem0_cli.commands.entities.console", console),
patch("mem0_cli.commands.entities.err_console", err_console), patch("mem0_cli.commands.entities.err_console", err_console),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_entities_list(mock_backend, "invalid", output="table") cmd_entities_list(mock_backend, "invalid", output="table")
@@ -944,7 +944,7 @@ class TestEntitiesDeleteCommand:
with ( with (
patch("mem0_cli.commands.entities.console", console), patch("mem0_cli.commands.entities.console", console),
patch("mem0_cli.commands.entities.err_console", err_console), patch("mem0_cli.commands.entities.err_console", err_console),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_entities_delete( cmd_entities_delete(
mock_backend, mock_backend,
@@ -1308,7 +1308,7 @@ class TestAgentMode:
patch("mem0_cli.commands.memory.console", console), patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console), patch("mem0_cli.commands.memory.err_console", err_console),
patch("sys.stdout", captured_stdout), patch("sys.stdout", captured_stdout),
pytest.raises((SystemExit, ClickExit)), pytest.raises((SystemExit, TyperExit)),
): ):
cmd_get(mock_backend, "bad-id", output="text") cmd_get(mock_backend, "bad-id", output="text")
+2 -1
View File
@@ -67,7 +67,8 @@ class TestConfig:
from mem0_cli.config import CONFIG_FILE from mem0_cli.config import CONFIG_FILE
mode = os.stat(CONFIG_FILE).st_mode & 0o777 mode = os.stat(CONFIG_FILE).st_mode & 0o777
assert mode == 0o600 if os.name != "nt":
assert mode == 0o600
def test_defaults_save_and_load(self, isolate_config): def test_defaults_save_and_load(self, isolate_config):
config = Mem0Config() config = Mem0Config()
+33
View File
@@ -4,6 +4,39 @@ description: "Release notes for the OpenClaw plugin and agent harness."
mode: "wide" mode: "wide"
--- ---
<Update label="2026-06-12" description="v1.0.13">
**Fixes:**
- **Custom categories payload:** `customCategories` (a `Record<string, string>` map) is now converted via the new `customCategoryMapToList()` helper into the `Array<Record<string, string>>` shape the Mem0 SDK expects on `add` calls — previously the raw object was passed as `custom_categories` and silently ignored ([#5345](https://github.com/mem0ai/mem0/pull/5345))
- **Skip runtime setup during metadata registration:** `register()` now detects `registrationMode === "cli-metadata"`, registers only the CLI commands, and returns early — avoiding backend initialization, service/tool registration, and hook installation during OpenClaw's metadata-only registration pass ([#5383](https://github.com/mem0ai/mem0/pull/5383))
**Security:**
- Bumped `mem0ai` from `3.0.3` to `3.0.7` (latest Node SDK) — includes the transitive axios CVE remediation shipped in `3.0.6` ([#5460](https://github.com/mem0ai/mem0/pull/5460))
- Added pnpm override `uuid@<11.1.1` → `>=11.1.1` to resolve an open MEDIUM Dependabot alert ([#5489](https://github.com/mem0ai/mem0/pull/5489))
**Improvements:**
- **Repo consolidation:** Plugin moved from repo-root `openclaw/` to `integrations/openclaw/`; `package.json` `repository.directory` updated to match so npm provenance links to the correct subdirectory ([#5491](https://github.com/mem0ai/mem0/pull/5491))
**Tests:**
- Added `customCategoryMapToList` unit tests and a `PlatformProvider` test asserting `custom_categories` is passed to the Mem0 SDK as a list ([#5345](https://github.com/mem0ai/mem0/pull/5345))
- Added a regression test asserting `cli-metadata` registration registers only CLI commands and triggers no runtime side effects ([#5383](https://github.com/mem0ai/mem0/pull/5383))
</Update>
<Update label="2026-06-02" description="v1.0.12">
**Docs:**
- **Agent Mode onboarding:** README now documents an autonomous setup path for AI agents — `mem0 init --agent --json` mints an evaluation Mem0 API key with no email, OTP, or browser and exports it as `MEM0_API_KEY` for `openclaw mem0 init`; a human owner can later run `mem0 init --email <email>` to claim ownership without disrupting the agent ([#5123](https://github.com/mem0ai/mem0/pull/5123))
**Security:**
- Added pnpm overrides to remediate advisories in transitive dependencies: `langsmith@<0.6.0` → `^0.6.0`, `picomatch@<2.3.2` → `^2.3.2`, `vite` → `^8.0.5`, and `@qdrant/js-client-rest` → `^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
**Dependencies:**
- Bumped `mem0ai` from `3.0.2` to `3.0.3` ([#5212](https://github.com/mem0ai/mem0/pull/5212))
- Bumped dev dependencies `@vitest/coverage-v8` and `vitest` from `^4.0.18` to `^4.1.7`; added `vite@^8.0.5` and `@qdrant/js-client-rest@^1.18.0` ([#5294](https://github.com/mem0ai/mem0/pull/5294))
</Update>
<Update label="2026-04-29" description="v1.0.11"> <Update label="2026-04-29" description="v1.0.11">
**New Features:** **New Features:**
+61
View File
@@ -7,6 +7,42 @@ mode: "wide"
<Tabs> <Tabs>
<Tab title="Python"> <Tab title="Python">
<Update label="2026-06-13" description="v2.0.6">
**New Features:**
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
**Bug Fixes:**
- **Memory:** Prevent a crash in `parse_vision_messages` when vision support is disabled ([#5487](https://github.com/mem0ai/mem0/pull/5487))
- **Vector Stores:** Expose the `https` option on the Qdrant vector store configuration so TLS endpoints can be targeted explicitly ([#5380](https://github.com/mem0ai/mem0/pull/5380))
- **Vector Stores:** Use valid S3 Vectors entity index names, fixing index operations that failed on invalid names ([#5416](https://github.com/mem0ai/mem0/pull/5416))
- **Vector Stores:** Fix `search()` crashing with a `TypeError` in the LangChain vector store when a result score is `None` ([#5072](https://github.com/mem0ai/mem0/pull/5072))
- **Vector Stores:** Use `is not None` instead of a truthiness check for vector/payload in the PGVector `update()` path, so valid empty/zero values are no longer skipped ([#5488](https://github.com/mem0ai/mem0/pull/5488))
- **Vector Stores:** Index the Valkey `memory` field as `TEXT` rather than `TAG` so full-text search behaves correctly ([#5443](https://github.com/mem0ai/mem0/pull/5443))
- **Vector Stores:** Implement `$not` filter support in the ChromaDB vector store ([#5485](https://github.com/mem0ai/mem0/pull/5485))
</Update>
<Update label="2026-06-10" description="v2.0.5">
**New Features:**
- **Memory:** Warn at init time when hybrid/BM25 search silently degrades to semantic-only because the configured vector store does not implement `keyword_search`. Affected stores: Chroma, FAISS, Cassandra, LangChain, Neptune Analytics, S3 Vectors, Supabase, TurboPuffer, Valkey ([#5444](https://github.com/mem0ai/mem0/pull/5444))
- **Memory:** Add opt-in `explain=True` parameter to `Memory.search()` and `AsyncMemory.search()`. When enabled, each result includes a `score_breakdown` dict with `semantic`, `keyword` (normalized BM25), `entity_boost`, and `temporal_boost` signals so callers can understand and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
**Bug Fixes:**
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) consistently across all backends. 11 adapters previously returned raw distance metrics (lower = better) — FAISS, Chroma, Milvus, Redis, Cassandra, PGVector, S3 Vectors, Supabase, Valkey, Azure MySQL, and Vertex AI Vector Search — causing incorrect ranking in multi-store setups ([#5391](https://github.com/mem0ai/mem0/pull/5391))
- **Memory:** Parallelize entity boost searches in `Memory.search()` and `AsyncMemory.search()`. Previously up to 8 entities were embedded and queried sequentially (16 serial round-trips with remote embedders); all entity lookups now run concurrently, eliminating multi-second latency on entity-rich queries ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Memory:** Reject empty or whitespace-only queries in `Memory.search()`, `AsyncMemory.search()`, `MemoryClient.search()`, and `AsyncMemoryClient.search()` before any embedding or API call is made. Also strips leading/trailing whitespace from valid queries ([#5258](https://github.com/mem0ai/mem0/pull/5258))
- **LLMs:** Add `is_reasoning_model: Optional[bool]` override to `BaseLlmConfig` (surfaced on `OpenAILlmConfig` and `AzureOpenAILlmConfig`). Fixes silent zero-extraction when using Azure deployments with versioned `gpt-5.x` names that the automatic name-based heuristic cannot recognize ([#5327](https://github.com/mem0ai/mem0/pull/5327))
- **LLMs:** Fix xAI LLM provider: add `XAIConfig` with `xai_base_url`, forward `tools`/`tool_choice` in `generate_response()`, and parse `tool_calls` in the response. Previously the provider raised `AttributeError` at init and silently dropped tool results ([#5190](https://github.com/mem0ai/mem0/pull/5190))
- **Vector Stores:** Fix PGVector `ConnectionPool` hang in Docker Compose environments where the app container starts before Postgres is DNS-resolvable — switched to `open=False` to avoid blocking constructor or silent zombie pool ([#5155](https://github.com/mem0ai/mem0/pull/5155))
- **Vector Stores:** Fix PGVector `sslmode` handling for PostgreSQL URIs — the `sslmode` query parameter is now correctly extracted and forwarded when building the async connection pool ([#5308](https://github.com/mem0ai/mem0/pull/5308))
- **Vector Stores:** Fix S3 Vectors `list()` not applying metadata filters — filtering is now done client-side after fetching, with pagination preserved and `top_k` applied after filtering to prevent pre-truncation of matching rows ([#5018](https://github.com/mem0ai/mem0/pull/5018))
- **Vector Stores:** Fix Upstash Vector `search()` routing all queries to the default namespace — `namespace` is now passed as a top-level keyword argument to `query_many()` instead of inside the per-query dict where it was silently ignored ([#5202](https://github.com/mem0ai/mem0/pull/5202))
- **Core:** Replace mutable default arguments with `None` sentinels in embedder configs and the proxy module, preventing cross-request state contamination ([#5302](https://github.com/mem0ai/mem0/pull/5302))
</Update>
<Update label="2026-05-27" description="v2.0.4"> <Update label="2026-05-27" description="v2.0.4">
**New Features:** **New Features:**
@@ -939,6 +975,31 @@ See the [OSS v1 to v2 migration guide](https://docs.mem0.ai/migration/oss-v1-to-
</Tab> </Tab>
<Tab title="TypeScript"> <Tab title="TypeScript">
<Update label="2026-06-13" description="v3.0.8">
**New Features:**
- **Memory:** Add a contextual OSS-to-Platform notices system that surfaces occasional, situation-aware messages (first run, scale/performance thresholds, slow queries, and when temporal/decay features are relevant) pointing to the corresponding Mem0 Platform capabilities; disable via `MEM0_TELEMETRY=false` ([#5494](https://github.com/mem0ai/mem0/pull/5494))
**Security:**
- **Dependencies:** Upgrade `@langchain/community` to `^1.1.18` to remediate CVE-2026-27795 and CVE-2026-26019 ([#5510](https://github.com/mem0ai/mem0/pull/5510))
- **Dependencies:** Resolve all open MEDIUM Dependabot alerts via pnpm overrides ([#5489](https://github.com/mem0ai/mem0/pull/5489))
</Update>
<Update label="2026-06-10" description="v3.0.7">
**New Features:**
- **Embeddings:** Add `LMStudioEmbedding` provider for local embeddings via the LM Studio server ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Memory:** Add opt-in `explain: true` option to `Memory.search()`. When enabled, each result includes a `scoreBreakdown` object with `semantic`, `keyword`, `entityBoost`, and `temporalBoost` fields so callers can inspect and tune retrieval ranking ([#5102](https://github.com/mem0ai/mem0/pull/5102))
**Bug Fixes:**
- **Memory:** Parallelize entity boost searches in `Memory.search()`. All entity embed + store lookups now run concurrently instead of sequentially, eliminating multi-second latency on entity-rich queries with remote embedding providers ([#5377](https://github.com/mem0ai/mem0/pull/5377))
- **Vector Stores:** Normalize similarity scores to `[0, 1]` (higher = better) — fixed score inversion in the Redis vector store adapter ([#5391](https://github.com/mem0ai/mem0/pull/5391))
- **Embeddings:** Request `encoding_format: "float"` from the OpenAI embedder in both `embed()` and `embedBatch()`. Fixes incorrect vector dimensions when using OpenAI-compatible proxies that default to base64 encoding ([#5170](https://github.com/mem0ai/mem0/pull/5170))
</Update>
<Update label="2026-06-01" description="v3.0.6"> <Update label="2026-06-01" description="v3.0.6">
**Security:** **Security:**
+2 -1
View File
@@ -76,6 +76,7 @@ Let's see the available parameters for the `qdrant` config:
| `path` | Path for the qdrant database | `/tmp/qdrant` | | `path` | Path for the qdrant database | `/tmp/qdrant` |
| `url` | Full URL for the qdrant server | `None` | | `url` | Full URL for the qdrant server | `None` |
| `api_key` | API key for the qdrant server | `None` | | `api_key` | API key for the qdrant server | `None` |
| `https` | Whether to force HTTPS on or off. `None` lets the client decide; set `False` for plain HTTP Qdrant with API key authentication. | `None` |
| `on_disk` | For enabling persistent storage | `False` | | `on_disk` | For enabling persistent storage | `False` |
</Tab> </Tab>
<Tab title="TypeScript"> <Tab title="TypeScript">
@@ -90,4 +91,4 @@ Let's see the available parameters for the `qdrant` config:
| `apiKey` | API key for the Qdrant server | `None` | | `apiKey` | API key for the Qdrant server | `None` |
| `onDisk` | For enabling persistent storage | `False` | | `onDisk` | For enabling persistent storage | `False` |
</Tab> </Tab>
</Tabs> </Tabs>
+1 -1
View File
@@ -28,7 +28,7 @@ echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc && source ~/.bashrc
```bash ```bash
# Install the plugin (MCP server, hooks, scripts) # Install the plugin (MCP server, hooks, scripts)
npx degit mem0ai/mem0/mem0-plugin ~/.gemini/config/plugins/mem0 npx degit mem0ai/mem0/integrations/mem0-plugin ~/.gemini/config/plugins/mem0
``` ```
This installs the MCP server, lifecycle hooks, and shared scripts. This installs the MCP server, lifecycle hooks, and shared scripts.
+1 -1
View File
@@ -43,7 +43,7 @@ bunx @mem0/opencode-plugin@latest install
**Or let your agent do it** — paste this into OpenCode: **Or let your agent do it** — paste this into OpenCode:
``` ```
Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/mem0-plugin/.opencode-plugin/README.md Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/integrations/mem0-plugin/.opencode-plugin/README.md
``` ```
All commands auto-add the plugin and MCP server to your `~/.config/opencode/opencode.json`. Restart OpenCode — you get the MCP server, lifecycle hooks, and all `/mem0:` slash commands. All commands auto-add the plugin and MCP server to your `~/.config/opencode/opencode.json`. Restart OpenCode — you get the MCP server, lifecycle hooks, and all `/mem0:` slash commands.
+3
View File
@@ -59,6 +59,7 @@ For advanced settings, create `~/.pi/agent/mem0-config.json`:
"userId": "your-username", "userId": "your-username",
"autoCapture": true, "autoCapture": true,
"defaultScope": "project", "defaultScope": "project",
"searchThreshold": 0.3,
"dream": { "dream": {
"enabled": true, "enabled": true,
"auto": true, "auto": true,
@@ -75,12 +76,14 @@ For advanced settings, create `~/.pi/agent/mem0-config.json`:
| `userId` | `string` | `$MEM0_USER_ID` or `"default"` | User identity for memory scoping | | `userId` | `string` | `$MEM0_USER_ID` or `"default"` | User identity for memory scoping |
| `autoCapture` | `boolean` | `true` | Store facts from conversations automatically | | `autoCapture` | `boolean` | `true` | Store facts from conversations automatically |
| `defaultScope` | `string` | `"project"` | Default memory scope: `project`, `session`, or `global` | | `defaultScope` | `string` | `"project"` | Default memory scope: `project`, `session`, or `global` |
| `searchThreshold` | `number` | `0.3` | Minimum similarity score (0–1) a memory must reach to count as a match for `/mem0-search`, `/mem0-forget`, and `/mem0-pin`, enforced on each result's relevance score. Raise it to be stricter; lower it if relevant results are missed. |
| `dream.enabled` | `boolean` | `true` | Enable dream consolidation | | `dream.enabled` | `boolean` | `true` | Enable dream consolidation |
| `dream.auto` | `boolean` | `true` | Auto-trigger dreams when thresholds are met | | `dream.auto` | `boolean` | `true` | Auto-trigger dreams when thresholds are met |
| `dream.minHours` | `number` | `24` | Minimum hours between auto-dreams | | `dream.minHours` | `number` | `24` | Minimum hours between auto-dreams |
| `dream.minSessions` | `number` | `5` | Minimum sessions before first auto-dream | | `dream.minSessions` | `number` | `5` | Minimum sessions before first auto-dream |
| `dream.minMemories` | `number` | `20` | Minimum memories before auto-dream triggers | | `dream.minMemories` | `number` | `20` | Minimum memories before auto-dream triggers |
## What's Included ## What's Included
| Component | Description | | Component | Description |
+2 -2
View File
@@ -398,9 +398,9 @@ Each subdirectory is a Claude Code Skill (`SKILL.md` + supporting assets). Load
### Editor Plugin (shared glue) ### Editor Plugin (shared glue)
Source: https://github.com/mem0ai/mem0/tree/main/mem0-plugin Source: https://github.com/mem0ai/mem0/tree/main/integrations/mem0-plugin
The `mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, Codex, OpenCode, and Antigravity. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`. The `integrations/mem0-plugin/` directory provides MCP server connection, lifecycle hooks, and skill bundling for Claude Code, Cursor, Codex, OpenCode, and Antigravity. It exposes 9 MCP tools: `add_memory`, `search_memories`, `get_memories`, `get_memory`, `update_memory`, `delete_memory`, `delete_all_memories`, `delete_entities`, `list_entities`.
Editor-specific setup docs (already listed above under `## Integrations > AI Coding Tools`): Editor-specific setup docs (already listed above under `## Integrations > AI Coding Tools`):
+19 -4
View File
@@ -6,9 +6,7 @@ versionFrom: "Open Source"
versionTo: "Platform" versionTo: "Platform"
--- ---
# Migrate from Open Source to Platform ## Overview
Move your Mem0 implementation to managed infrastructure with enterprise features.
| Scope | Effort | Downtime | | Scope | Effort | Downtime |
| --------------------- | -------------- | ---------------------------- | | --------------------- | -------------- | ---------------------------- |
@@ -30,12 +28,29 @@ Move your Mem0 implementation to managed infrastructure with enterprise features
- **Production Grade**: Auto-scaling, high availability, dedicated support - **Production Grade**: Auto-scaling, high availability, dedicated support
</Info> </Info>
## Plan ### Plan
1. **Sign up**: Create an account on <a href="https://app.mem0.ai?utm_source=oss&utm_medium=migration-oss-to-platform" rel="nofollow">Mem0 Platform</a>. 1. **Sign up**: Create an account on <a href="https://app.mem0.ai?utm_source=oss&utm_medium=migration-oss-to-platform" rel="nofollow">Mem0 Platform</a>.
2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key. 2. **Get API Key**: Navigate to **Settings > API Keys** and generate a new key.
3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`. 3. **Review Usage**: Identify where you instantiate `Memory` and where you call `search` or `get_all`.
## Migrate with Agent Skill
Paste this prompt into your coding agent. It uses a migration skill to produce a plan; once you review and approve it, the agent implements the changes.
```text
Migrate my project from Mem0 OSS to the Mem0 Platform SDK using the
mem0-oss-to-platform skill in the mem0ai/mem0 repo, at
skills/mem0-oss-to-platform/
Get the skill whichever way is easiest:
- install it: npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
- if the mem0 repo is cloned locally, read it from skills/mem0-oss-to-platform/
- otherwise fetch that folder from github.com/mem0ai/mem0 (SKILL.md + references/)
Then read SKILL.md and begin the migration.
```
## Migrate ## Migrate
### 1. Import Memories Into Platform ### 1. Import Memories Into Platform
+2
View File
@@ -45,10 +45,12 @@ Let your assistant execute an end-to-end workflow in an existing repo. Invoked a
```bash ```bash
npx skills add https://github.com/mem0ai/mem0 --skill mem0-integrate 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-test-integration
npx skills add https://github.com/mem0ai/mem0 --skill mem0-oss-to-platform
``` ```
- `/mem0-integrate` — wire Mem0 into an existing repository using a goal-driven, test-first pipeline. Detects the stack, asks whether to use Platform or OSS, writes failing tests first, and keeps the integration additive and feature-flagged. - `/mem0-integrate` — wire Mem0 into an existing repository using a goal-driven, test-first pipeline. Detects the stack, asks whether to use Platform or OSS, writes failing tests first, and keeps the integration additive and feature-flagged.
- `/mem0-test-integration` — verify what `/mem0-integrate` produced. Runs the repo's native test suite and a real end-to-end smoke flow against your API key, then produces a scorecard. - `/mem0-test-integration` — verify what `/mem0-integrate` produced. Runs the repo's native test suite and a real end-to-end smoke flow against your API key, then produces a scorecard.
- `/mem0-oss-to-platform` — migrate an existing project from Mem0 OSS to the hosted Platform SDK. Audits where Mem0 is used, writes a reviewable migration plan, then executes it on approval.
See the [skills index](https://github.com/mem0ai/mem0/tree/main/skills) for the full catalog. See the [skills index](https://github.com/mem0ai/mem0/tree/main/skills) for the full catalog.
@@ -16,10 +16,10 @@ type RetrievedMemory = {
type NewMemory = { type NewMemory = {
id: string; id: string;
data: { data?: {
memory: string; memory: string;
}; };
event: "ADD" | "DELETE"; event: "ADD" | "UPDATE" | "DELETE" | "GET";
}; };
type NewMemoryAnnotation = { type NewMemoryAnnotation = {
@@ -47,14 +47,16 @@ const useMemories = (): Memory[] => {
() => () =>
annotations?.filter(isMemoryAnnotation).flatMap((a) => { annotations?.filter(isMemoryAnnotation).flatMap((a) => {
if (a.type === "mem0-update") { if (a.type === "mem0-update") {
return a.memories.map( return a.memories
(m): Memory => ({ .filter((m): m is NewMemory & { data: { memory: string } } => m.data != null)
event: m.event, .map(
id: m.id, (m): Memory => ({
memory: m.data.memory, event: m.event,
score: 1, id: m.id,
}) memory: m.data.memory,
); score: 1,
})
);
} else if (a.type === "mem0-get") { } else if (a.type === "mem0-get") {
return a.memories.map((m) => ({ return a.memories.map((m) => ({
event: "GET", event: "GET",
@@ -555,7 +555,7 @@
"# - Enables creation of AI agents with long-term memory and learning abilities.\n", "# - Enables creation of AI agents with long-term memory and learning abilities.\n",
"# - Improves consistency and reduces repetition in user-agent interactions.\n", "# - Improves consistency and reduces repetition in user-agent interactions.\n",
"\n", "\n",
"from cookbooks.helper.mem0_teachability import Mem0Teachability\n", "from helper.mem0_teachability import Mem0Teachability\n",
"\n", "\n",
"teachability = Mem0Teachability(\n", "teachability = Mem0Teachability(\n",
" verbosity=2, # for visibility of what's happening\n", " verbosity=2, # for visibility of what's happening\n",
@@ -1,6 +1,6 @@
{ {
"name": "mem0", "name": "mem0",
"version": "0.2.9", "version": "0.2.10",
"description": "Persistent memory for Claude Code. Remembers decisions, patterns, and preferences across sessions.", "description": "Persistent memory for Claude Code. Remembers decisions, patterns, and preferences across sessions.",
"author": { "author": {
"name": "Mem0", "name": "Mem0",
@@ -1,6 +1,6 @@
{ {
"name": "mem0", "name": "mem0",
"version": "0.2.9", "version": "0.2.10",
"description": "Persistent memory for Codex. Remembers decisions, patterns, and preferences across sessions.", "description": "Persistent memory for Codex. Remembers decisions, patterns, and preferences across sessions.",
"author": { "author": {
"name": "Mem0", "name": "Mem0",
@@ -1,6 +1,6 @@
{ {
"name": "mem0", "name": "mem0",
"version": "0.2.9", "version": "0.2.10",
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search using the Mem0 Platform MCP server.", "description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search using the Mem0 Platform MCP server.",
"author": { "author": {
"name": "Mem0", "name": "Mem0",
@@ -2,13 +2,14 @@
All notable changes to the `@mem0/opencode-plugin` will be documented in this file. All notable changes to the `@mem0/opencode-plugin` will be documented in this file.
## 0.1.3 — File-context injection, session summaries & activity timeline ## 0.1.3 — File-context injection, session summaries & activity timeline, anonymous telemetry
### Added ### Added
- **File-context injection (`tool.execute.before` / Read):** Before the agent reads a file, the plugin searches mem0 for memories referencing that file path and injects prior work as system context. Gates on file size (>= 1,500 bytes). Gives the agent "I've worked on this file before" awareness automatically. - **File-context injection (`tool.execute.before` / Read):** Before the agent reads a file, the plugin searches mem0 for memories referencing that file path and injects prior work as system context. Gates on file size (>= 1,500 bytes). Gives the agent "I've worked on this file before" awareness automatically.
- **Stop hook session summary (`experimental.session.compacting`):** Enhanced session compaction to store a structured `session_summary` memory with `infer=True`, letting the mem0 backend AI extract key facts (request, decisions, learnings, next steps). Previously only stored a raw stats string. - **Stop hook session summary (`experimental.session.compacting`):** Enhanced session compaction to store a structured `session_summary` memory with `infer=True`, letting the mem0 backend AI extract key facts (request, decisions, learnings, next steps). Previously only stored a raw stats string.
- **SessionStart activity timeline:** The initial memory loading now formats recent memories with type icons (⚖️ decision, 🔴 bug_fix, 🔵 task_learning, etc.) and relative age indicators (2h ago, 1d ago) instead of bare text. Provides a visual "Recent Activity" timeline on first message. - **SessionStart activity timeline:** The initial memory loading now formats recent memories with type icons (⚖️ decision, 🔴 bug_fix, 🔵 task_learning, etc.) and relative age indicators (2h ago, 1d ago) instead of bare text. Provides a visual "Recent Activity" timeline on first message.
- **PostHog telemetry (`telemetry.ts`):** Anonymous, fire-and-forget usage events. Opt out with `MEM0_TELEMETRY=false`. Only fires when an API key is present; never sends memory content, prompts, or the API key — only an anonymized `sha256(apiKey)[:32]` identity plus event type, platform, and plugin version. Emits the same schema as the Mem0 editor plugin (`plugin.*` events, `source: "plugin"`, `platform: "opencode"`) so OpenCode appears as a `platform` in the shared plugin dashboard. Events: `plugin.session_start` (with memory count) and `plugin.tool_use` (`add` / `search` / `update` / `delete`).
### Changed ### Changed
@@ -17,7 +17,7 @@ opencode plugin @mem0/opencode-plugin
**Or let your agent do it** — paste this into OpenCode: **Or let your agent do it** — paste this into OpenCode:
``` ```
Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/mem0-plugin/.opencode-plugin/README.md Install @mem0/opencode-plugin by following https://raw.githubusercontent.com/mem0ai/mem0/main/integrations/mem0-plugin/.opencode-plugin/README.md
``` ```
All commands auto-add the plugin and MCP server to your `~/.config/opencode/opencode.json`. No manual config needed. All commands auto-add the plugin and MCP server to your `~/.config/opencode/opencode.json`. No manual config needed.
@@ -6,7 +6,7 @@
"name": "@mem0/opencode-plugin", "name": "@mem0/opencode-plugin",
"dependencies": { "dependencies": {
"@opencode-ai/plugin": "^1.0.162", "@opencode-ai/plugin": "^1.0.162",
"mem0ai": "^3.0.5", "mem0ai": "^3.0.7",
}, },
"devDependencies": { "devDependencies": {
"bun-types": ">=1.3.14", "bun-types": ">=1.3.14",
@@ -462,7 +462,7 @@
"md5": ["md5@2.3.0", "", { "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" } }, "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g=="], "md5": ["md5@2.3.0", "", { "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" } }, "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g=="],
"mem0ai": ["mem0ai@3.0.5", "", { "dependencies": { "axios": "^1.15.2", "openai": "^4.93.0", "uuid": "9.0.1", "zod": "^3.24.1" }, "peerDependencies": { "@anthropic-ai/sdk": "^0.40.1", "@azure/identity": "^4.0.0", "@azure/search-documents": "^12.0.0", "@cloudflare/workers-types": "^4.20250504.0", "@google/genai": "^1.2.0", "@langchain/core": "^1.1.47", "@mistralai/mistralai": "^1.5.2", "@qdrant/js-client-rest": "1.13.0", "@supabase/supabase-js": "^2.49.1", "@types/jest": "29.5.14", "@types/pg": "8.11.0", "better-sqlite3": "^12.6.2", "cloudflare": "^4.2.0", "compromise": "^14.0.0", "groq-sdk": "0.3.0", "natural": "^8.0.1", "ollama": "^0.5.14", "pg": "8.11.3", "redis": "^4.6.13" } }, "sha512-W/R59d5fMpUGHhPEnyoo36GSz5NFJbAs+vS4BxoIvE+t19mIJfoz/2FJSKIw80mT8AkeNYpDfzc/DYRu2IzYIw=="], "mem0ai": ["mem0ai@3.0.7", "", { "dependencies": { "axios": "^1.16.0", "openai": "^4.93.0", "uuid": "9.0.1", "zod": "^3.24.1" }, "peerDependencies": { "@anthropic-ai/sdk": "^0.40.1", "@azure/identity": "^4.0.0", "@azure/search-documents": "^12.0.0", "@cloudflare/workers-types": "^4.20250504.0", "@google/genai": "^1.40.0", "@langchain/core": "^1.1.47", "@mistralai/mistralai": "^1.5.2", "@qdrant/js-client-rest": "^1.18.0", "@supabase/supabase-js": "^2.49.1", "@types/jest": "29.5.14", "@types/pg": "8.11.0", "better-sqlite3": "^12.6.2", "cloudflare": "^4.2.0", "compromise": "^14.0.0", "groq-sdk": "0.3.0", "natural": "^8.0.1", "ollama": "^0.5.14", "pg": "8.11.3", "redis": "^4.6.13" } }, "sha512-CUHzX7DyeKTHcI3aDsSqY9LXTD7GcFxf988796TuOa4yJgGuF2Xd2NROcBhVFRo3r9y8fVmbo3c5TF9jv1KlKw=="],
"memjs": ["memjs@1.3.2", "", {}, "sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg=="], "memjs": ["memjs@1.3.2", "", {}, "sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg=="],
@@ -9,6 +9,7 @@ import { existsSync, readdirSync, cpSync, mkdirSync, readFileSync, writeFileSync
import { homedir } from "os"; import { homedir } from "os";
import { join } from "path"; import { join } from "path";
import { createHash } from "crypto"; import { createHash } from "crypto";
import { captureEvent } from "./telemetry";
async function getUserId(): Promise<string> { async function getUserId(): Promise<string> {
if (process.env.MEM0_USER_ID) return process.env.MEM0_USER_ID; if (process.env.MEM0_USER_ID) return process.env.MEM0_USER_ID;
@@ -368,6 +369,8 @@ const Mem0Plugin: Plugin = async (ctx) => {
}); });
} catch {} } catch {}
} }
captureEvent("session_start", { memory_count: memoryCount }, apiKey);
} }
if (NUDGE_RE.test(safeText)) { if (NUDGE_RE.test(safeText)) {
@@ -602,6 +605,17 @@ const Mem0Plugin: Plugin = async (ctx) => {
if (MEM0_MCP_RE.test(toolName)) { if (MEM0_MCP_RE.test(toolName)) {
if (toolName.includes("add_memory")) stats.adds++; if (toolName.includes("add_memory")) stats.adds++;
if (toolName.includes("search")) stats.searches++; if (toolName.includes("search")) stats.searches++;
const tool = toolName.includes("add_memory")
? "add_memory"
: toolName.includes("search")
? "search_memories"
: toolName.includes("delete")
? "delete_memory"
: toolName.includes("update")
? "update_memory"
: "other";
captureEvent("tool_use", { tool }, apiKey);
} }
if (toolName === "bash" && toolOutput.length >= 50) { if (toolName === "bash" && toolOutput.length >= 50) {
@@ -30,7 +30,7 @@
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/mem0ai/mem0", "url": "https://github.com/mem0ai/mem0",
"directory": "mem0-plugin/.opencode-plugin" "directory": "integrations/mem0-plugin/.opencode-plugin"
}, },
"files": [ "files": [
"dist", "dist",
@@ -59,7 +59,7 @@
}, },
"dependencies": { "dependencies": {
"@opencode-ai/plugin": "^1.0.162", "@opencode-ai/plugin": "^1.0.162",
"mem0ai": "^3.0.5" "mem0ai": "^3.0.7"
}, },
"devDependencies": { "devDependencies": {
"bun-types": ">=1.3.14", "bun-types": ">=1.3.14",
@@ -0,0 +1,51 @@
import { afterEach, describe, expect, test } from "bun:test";
import { buildEvent, captureEvent, isTelemetryEnabled } from "./telemetry";
const KEY = "m0-testkey123";
afterEach(() => {
delete process.env.MEM0_TELEMETRY;
});
describe("opencode telemetry", () => {
test("buildEvent uses the shared plugin.* schema with platform=opencode", () => {
const payload = buildEvent("session_start", { memory_count: 5 }, KEY);
expect(payload).not.toBeNull();
const props = payload!.properties as Record<string, unknown>;
expect(payload!.event).toBe("plugin.session_start");
expect(props.source).toBe("plugin");
expect(props.platform).toBe("opencode");
expect(props.memory_count).toBe(5);
expect(props.$process_person_profile).toBe(false);
expect(typeof props.plugin_version).toBe("string");
});
test("distinct_id is sha256(apiKey)[:32] — matches the editor plugin", async () => {
const { createHash } = await import("node:crypto");
const expected = createHash("sha256").update(KEY).digest("hex").slice(0, 32);
expect(buildEvent("session_start", {}, KEY)!.distinct_id).toBe(expected);
});
test("system properties win over caller-supplied ones", () => {
const props = buildEvent("x", { platform: "HACK", source: "HACK" }, KEY)!
.properties as Record<string, unknown>;
expect(props.platform).toBe("opencode");
expect(props.source).toBe("plugin");
});
test("returns null without an API key (no anonymous events)", () => {
expect(buildEvent("session_start", {}, undefined)).toBeNull();
});
test("opt-out via MEM0_TELEMETRY disables events", () => {
process.env.MEM0_TELEMETRY = "false";
expect(isTelemetryEnabled()).toBe(false);
expect(buildEvent("session_start", {}, KEY)).toBeNull();
});
test("captureEvent never throws (and sends nothing when opted out)", () => {
process.env.MEM0_TELEMETRY = "false";
expect(() => captureEvent("session_start", {}, KEY)).not.toThrow();
expect(() => captureEvent("session_start", {}, undefined)).not.toThrow();
});
});
@@ -0,0 +1,104 @@
/**
* Plugin telemetry for the Mem0 OpenCode plugin — anonymous usage tracking
* via PostHog.
*
* Emits the SAME event schema as the Mem0 editor plugin's telemetry.py
* (event names prefixed `plugin.`, `source: "plugin"`, `platform: "opencode"`,
* `distinct_id = sha256(apiKey)[:32]`) so OpenCode shows up as just another
* `platform` value in the shared plugin dashboard instead of a separate
* event namespace.
*
* Fire-and-forget: never throws, never blocks, failures are swallowed. Only
* fires when an API key is present (same as the editor plugin — anonymous
* installs without a key emit nothing). Disable with MEM0_TELEMETRY=false.
*
* Never sends: memory content, API keys, raw user/project IDs. Only sends:
* event type, platform, plugin version, anonymized hash of the API key.
*/
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
const REQUEST_TIMEOUT_MS = 2_000;
function _loadPluginVersion(): string {
// Source context: telemetry.ts sits next to package.json (./).
// Bundled context: dist/index.js sits one level below it (../).
for (const rel of ["./package.json", "../package.json"]) {
try {
const pkg = JSON.parse(readFileSync(new URL(rel, import.meta.url), "utf-8"));
if (pkg?.name === "@mem0/opencode-plugin" && pkg.version) return pkg.version;
} catch {
/* try next candidate */
}
}
return "unknown";
}
const PLUGIN_VERSION = _loadPluginVersion();
export function isTelemetryEnabled(): boolean {
const val = process.env.MEM0_TELEMETRY;
if (val === undefined) return true;
const s = val.toLowerCase();
return s !== "false" && s !== "0" && s !== "no" && s !== "off";
}
function distinctId(apiKey: string): string {
// Matches telemetry.py `_distinct_id()` so the same user is one person in
// PostHog whether they use OpenCode or any other Mem0 editor plugin.
return createHash("sha256").update(apiKey).digest("hex").slice(0, 32);
}
/**
* Build the PostHog event payload, or null when telemetry is disabled or no
* API key is available. Pure (aside from env/version reads) and exported for
* testing. System-controlled properties are applied last so a caller cannot
* override `source`/`platform`/etc.
*/
export function buildEvent(
eventType: string,
properties: Record<string, unknown>,
apiKey: string | undefined,
): Record<string, unknown> | null {
if (!isTelemetryEnabled() || !apiKey) return null;
return {
api_key: POSTHOG_API_KEY,
distinct_id: distinctId(apiKey),
event: `plugin.${eventType}`,
properties: {
...properties,
source: "plugin",
platform: "opencode",
plugin_version: PLUGIN_VERSION,
os: process.platform,
sample_rate: 1.0,
$process_person_profile: false,
$lib: "posthog-node",
},
};
}
/** Send a usage event, fire-and-forget. Never throws, never blocks. */
export function captureEvent(
eventType: string,
properties: Record<string, unknown>,
apiKey: string | undefined,
): void {
const payload = buildEvent(eventType, properties, apiKey);
if (!payload) return;
try {
void fetch(POSTHOG_HOST, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
}).catch(() => {
/* fire-and-forget */
});
} catch {
/* never throw */
}
}
@@ -16,5 +16,5 @@
"emitDeclarationOnly": true "emitDeclarationOnly": true
}, },
"include": ["**/*"], "include": ["**/*"],
"exclude": ["node_modules", "dist"] "exclude": ["node_modules", "dist", "**/*.test.ts"]
} }
@@ -2,6 +2,21 @@
All notable changes to the Mem0 plugin will be documented in this file. All notable changes to the Mem0 plugin will be documented in this file.
## 0.2.10 — Accurate per-editor telemetry attribution
### Fixed
- **Antigravity counted as Claude Code:** `detect_platform()` (`scripts/telemetry.py`) now checks `ANTIGRAVITY_PLUGIN_ROOT` before the `CLAUDE_PLUGIN_ROOT` branch. Antigravity sets both env vars for compatibility, so every Antigravity session was previously attributed to `claude-code`. Telemetry now reports `platform: "antigravity"`.
- **Codex fell back to the generic `plugin` bucket:** Codex installs standalone hooks with absolute paths via `install_codex_hooks.py`, so `PLUGIN_ROOT` is never set at runtime and platform auto-detection failed. Each command in `hooks/codex-hooks.json` now pins `MEM0_PLATFORM=codex` inline (Codex runs hook commands through a shell). Telemetry now reports `platform: "codex"`.
- **Cursor attribution depended on the host env:** Cursor's `*_cursor.sh` wrappers delegate to the shared hook scripts, whose platform detection relied on Cursor exporting `CURSOR_PLUGIN_ROOT` to the subprocess. All five Cursor wrappers now `export MEM0_PLATFORM=cursor` before delegating.
- **`plugin_version` was identical for every editor:** telemetry read `.claude-plugin/plugin.json` for all bash-hook editors, so Antigravity reported `0.2.10` instead of its real `0.1.2`. `_load_plugin_version()` now reads the manifest matching the detected platform, so each editor reports its own version.
### Added
- **`MEM0_PLATFORM` override in `detect_platform()`:** An explicit platform marker that wins over env-var auto-detection, letting each editor label its telemetry reliably. New tests in `tests/test_telemetry.py` cover the override, Antigravity attribution, and the Cursor/Codex platform-pinning contracts.
> Attribution fixes apply to telemetry emitted after users upgrade to this version; PostHog does not backfill past events.
## 0.2.9 — File-context injection, session summaries & activity timeline ## 0.2.9 — File-context injection, session summaries & activity timeline
### Added ### Added
@@ -90,14 +90,14 @@ git clone https://github.com/mem0ai/mem0.git ~/codex-plugins/mem0-source
codex plugin marketplace add ~/codex-plugins/mem0-source codex plugin marketplace add ~/codex-plugins/mem0-source
``` ```
This points Codex at the repo's `.agents/plugins/marketplace.json`, which references `mem0-plugin/` as the local source. Restart Codex, run `/plugins`, and install **Mem0** from the **Mem0 Plugins** marketplace. This points Codex at the repo's `.agents/plugins/marketplace.json`, which references `integrations/mem0-plugin/` as the local source. Restart Codex, run `/plugins`, and install **Mem0** from the **Mem0 Plugins** marketplace.
> **Don't combine with Option A.** The plugin manifest auto-registers `mem0` as an MCP server via `mem0-plugin/.codex-mcp.json` — adding a manual `[mcp_servers.mem0]` block would duplicate the registration. > **Don't combine with Option A.** The plugin manifest auto-registers `mem0` as an MCP server via `integrations/mem0-plugin/.codex-mcp.json` — adding a manual `[mcp_servers.mem0]` block would duplicate the registration.
**Optional — enable lifecycle hooks.** Codex doesn't auto-wire hooks from plugin manifests; it only reads `~/.codex/hooks.json` (or `<repo>/.codex/hooks.json`) ([docs](https://developers.openai.com/codex/hooks)). Run the bundled installer once to merge Mem0's entries: **Optional — enable lifecycle hooks.** Codex doesn't auto-wire hooks from plugin manifests; it only reads `~/.codex/hooks.json` (or `<repo>/.codex/hooks.json`) ([docs](https://developers.openai.com/codex/hooks)). Run the bundled installer once to merge Mem0's entries:
```bash ```bash
python3 ~/codex-plugins/mem0-source/mem0-plugin/scripts/install_codex_hooks.py python3 ~/codex-plugins/mem0-source/integrations/mem0-plugin/scripts/install_codex_hooks.py
``` ```
This merges three entries into `~/.codex/hooks.json` with absolute paths pointing into your clone: This merges three entries into `~/.codex/hooks.json` with absolute paths pointing into your clone:
@@ -190,7 +190,7 @@ See [OpenCode integration docs](https://docs.mem0.ai/integrations/opencode) for
```bash ```bash
# Install the plugin (MCP server, hooks, scripts) # Install the plugin (MCP server, hooks, scripts)
npx degit mem0ai/mem0/mem0-plugin ~/.gemini/config/plugins/mem0 npx degit mem0ai/mem0/integrations/mem0-plugin ~/.gemini/config/plugins/mem0
``` ```
This installs the MCP server, lifecycle hooks, and shared scripts. This installs the MCP server, lifecycle hooks, and shared scripts.
@@ -276,10 +276,10 @@ The background setup is idempotent and runs once per account (cached in `~/.mem0
```bash ```bash
# Dry-run -- prints current vs proposed, no changes: # Dry-run -- prints current vs proposed, no changes:
python mem0-plugin/scripts/setup_coding_categories.py python integrations/mem0-plugin/scripts/setup_coding_categories.py
# Write explicitly: # Write explicitly:
python mem0-plugin/scripts/setup_coding_categories.py --apply python integrations/mem0-plugin/scripts/setup_coding_categories.py --apply
``` ```
Requires the `mem0ai` Python SDK (`pip install mem0ai`) and `MEM0_API_KEY` set. `project.update(custom_categories=[...])` always replaces the full list. Requires the `mem0ai` Python SDK (`pip install mem0ai`) and `MEM0_API_KEY` set. `project.update(custom_categories=[...])` always replaces the full list.
@@ -6,7 +6,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/block_memory_write.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/block_memory_write.sh",
"timeout": 3 "timeout": 3
} }
] ]
@@ -16,7 +16,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/enforce_metadata_defaults.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/enforce_metadata_defaults.sh",
"timeout": 3 "timeout": 3
} }
] ]
@@ -26,7 +26,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_file_read.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_file_read.sh",
"timeout": 5 "timeout": 5
} }
] ]
@@ -38,7 +38,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_session_start.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_session_start.sh",
"statusMessage": "Loading mem0 context..." "statusMessage": "Loading mem0 context..."
} }
] ]
@@ -49,7 +49,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_user_prompt.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_user_prompt.sh",
"statusMessage": "Checking memory relevance...", "statusMessage": "Checking memory relevance...",
"timeout": 12 "timeout": 12
} }
@@ -62,7 +62,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_post_tool_use.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_post_tool_use.sh",
"timeout": 3 "timeout": 3
} }
] ]
@@ -72,7 +72,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_bash_output.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_bash_output.sh",
"timeout": 12 "timeout": 12
} }
] ]
@@ -83,7 +83,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_stop.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_stop.sh",
"timeout": 30 "timeout": 30
} }
] ]
@@ -94,7 +94,7 @@
"hooks": [ "hooks": [
{ {
"type": "command", "type": "command",
"command": "${PLUGIN_ROOT}/scripts/on_pre_compact.sh", "command": "MEM0_PLATFORM=codex ${PLUGIN_ROOT}/scripts/on_pre_compact.sh",
"statusMessage": "Preparing pre-compaction summary..." "statusMessage": "Preparing pre-compaction summary..."
} }
] ]

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

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