Compare commits

..
Author SHA1 Message Date
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
338 changed files with 5477 additions and 4867 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",
+1 -1
View File
@@ -10,7 +10,7 @@
"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.9"
} }
+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",
+1 -1
View File
@@ -10,7 +10,7 @@
"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.9"
} }
+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
+49 -24
View File
@@ -22,11 +22,13 @@ 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/` | | `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) |
@@ -49,8 +51,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 +75,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 +164,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 +182,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 +344,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,11 +383,11 @@ 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.
@@ -402,24 +404,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 +451,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
+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,
},
}); });
+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")
+34
View File
@@ -7,6 +7,26 @@ mode: "wide"
<Tabs> <Tabs>
<Tab title="Python"> <Tab title="Python">
<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 +959,20 @@ 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-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:**
+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`):
@@ -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",
@@ -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.
@@ -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",
@@ -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.

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