Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 94c3fe9f23 | |||
| 947ac79818 | |||
| 8127e8bd47 | |||
| 5fd01d284a | |||
| 70c676c8c4 | |||
| a2d8a8a849 | |||
| fb6d5e1917 | |||
| ccd216cff0 | |||
| 545306db5a | |||
| 8d6c001966 | |||
| 989c7da0fc | |||
| d675cf68ad | |||
| 2c6ff619d1 | |||
| f4acc89a29 | |||
| 43849c6e9d | |||
| 47a69e1e72 | |||
| ea9bbcabed | |||
| 0cddc36d52 | |||
| 83b07b1537 | |||
| 8c02c425a5 | |||
| f8082a7345 | |||
| 5d38e3703a | |||
| fd8fd087ea | |||
| a214ec37bc | |||
| 8b38da9ab8 | |||
| 17852dc648 | |||
| a39a802bbc | |||
| 19f7134082 | |||
| a8d3634312 | |||
| 1a5c7ad28c | |||
| 4e38b057fd | |||
| 3362999095 | |||
| 012cd32c3a | |||
| e4e0307ae6 | |||
| 84bf468176 | |||
| f135cb9949 | |||
| f5220ff8d4 | |||
| 0df3e4b87d | |||
| b51f7692f0 | |||
| dc7f88363f | |||
| c7ee362aff | |||
| d873892dad | |||
| 02f7a9b2c4 | |||
| 73e7b8763a | |||
| dae67f74f5 | |||
| 9a7924befd | |||
| 3cf41878ea | |||
| c33ca27f5e | |||
| 71fba8d464 | |||
| 19cb89aff4 | |||
| fdfb763d6e | |||
| 0070e08e01 | |||
| 39bc023305 | |||
| b1342a3408 | |||
| b717e38785 | |||
| dc82354e14 | |||
| 4ddee9c51d | |||
| 7e09615571 | |||
| d18e751dec | |||
| 8d5b7865bd | |||
| 9b565da8e3 | |||
| 48d0d0cd9c | |||
| feb12852c0 | |||
| 5af797834c | |||
| 4fa4839077 | |||
| 3599aa75ed | |||
| 1de6499b8a | |||
| ed38ddf873 | |||
| 530d802b55 | |||
| d3334fa5f1 | |||
| 52b02c7cc1 | |||
| 001c235229 | |||
| bf2d591b27 | |||
| b4c50550bf | |||
| 290de24bb8 | |||
| ef6f51d977 | |||
| a10c0cd030 | |||
| 956bf4f88e | |||
| 0f172c2890 | |||
| 696455fd62 | |||
| 9e99eaadbc | |||
| 02ff6c5595 | |||
| a0329f047b | |||
| c50a2bfb8f | |||
| bfb51c6b93 | |||
| a133287015 | |||
| c883f52130 | |||
| 96d45b78c7 | |||
| ba2fb9f4c3 | |||
| 14c431735b | |||
| d70cc00ab3 | |||
| c427a453a8 | |||
| f5b4300449 | |||
| 71f2ebefa3 | |||
| 35a125585e | |||
| 4debc58a83 | |||
| b42cfdd5c8 | |||
| 6fe6140dba | |||
| b05dc2740f | |||
| 4a0a9a92a6 | |||
| beea626f0a | |||
| 3f39fba28f | |||
| 12c47f5249 | |||
| 3f717e5459 | |||
| 18021dd106 | |||
| fad0e0e415 | |||
| 1112be3e5e | |||
| 6052252250 | |||
| deca4bd3a5 | |||
| 4cfcd0241a | |||
| b54710a3c3 | |||
| 4cfa98f626 | |||
| b830b99abe | |||
| 45208feebb | |||
| 3ac9ba4b50 | |||
| 965140eb19 | |||
| 6e6f5b8d59 | |||
| dd54e387de |
@@ -8,7 +8,7 @@
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./integrations/mem0-plugin"
|
||||
"path": "./integrations/codex-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": "./integrations/mem0-plugin",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search to Claude workflows.",
|
||||
"version": "0.2.13"
|
||||
"source": "./integrations/claude-code-plugin",
|
||||
"description": "Cross-session memory and token savings for coding agents.",
|
||||
"version": "0.3.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"name": "mem0",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./integrations/mem0-plugin"
|
||||
"path": "./integrations/codex-plugin"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
"plugins": [
|
||||
{
|
||||
"name": "mem0",
|
||||
"source": "./integrations/mem0-plugin",
|
||||
"description": "Mem0 memory layer for AI applications. Add persistent memory, personalization, and semantic search.",
|
||||
"version": "0.2.13"
|
||||
"source": "./integrations/cursor-plugin",
|
||||
"description": "Cross-session memory and token savings for coding agents.",
|
||||
"version": "0.3.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
# CI/CD and repository automation (`.github/`)
|
||||
|
||||
> **Do not modify any workflow without explicit approval from a maintainer.** Publishing
|
||||
> credentials are bound to workflow filenames, and the gate workflows decide whether
|
||||
> contributions are accepted. Read this file before proposing any change here.
|
||||
|
||||
## CI: one gate, many pipelines
|
||||
|
||||
`ci-gate.yml` (**CI Gate**) is the single entry point. It runs on every PR, detects which packages changed, and calls only the relevant package workflows as reusable workflows (`workflow_call`). Its final `CI Gate` job aggregates the results: skipped pipelines pass, failed or cancelled ones fail. It is the **only CI 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 live in the gate's path filters instead.
|
||||
|
||||
| Workflow | File | Standalone triggers | Runs |
|
||||
|----------|------|---------------------|------|
|
||||
| CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates everything below |
|
||||
| Python SDK | `ci.yml` | Push to main | Ruff + pytest on Python 3.10, 3.11, 3.12 |
|
||||
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main (`mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
|
||||
| Python CLI | `cli-python-ci.yml` | Push to main (`cli/python/`), manual | Ruff + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||
| Node CLI | `cli-node-ci.yml` | Push to main (`cli/node/`), manual | Biome + tsc + vitest + tsup on Node 20, 22 |
|
||||
| OpenClaw | `openclaw-checks.yml` | Push to main (`integrations/openclaw/`), manual | tsc + vitest (Codecov) + tsup on Node 20, 22 |
|
||||
| Agent Plugins Python | `agent-plugins-python-checks.yml` | Push to main (shared Python core and native/portable plugin directories), manual | Runtime tests on Python 3.10; full pytest on 3.11, 3.12; ruff + generated-package drift on 3.12 |
|
||||
| Agent Plugins TypeScript | `agent-plugins-typescript-checks.yml` | Push to main (`integrations/agent-plugin-core/typescript/`), manual | tsc + node:test on Node 22 |
|
||||
| OpenCode Plugin | `opencode-plugin-checks.yml` | Push to main (`integrations/opencode-plugin/`), manual | Bun: tsc + build + dist artifact check |
|
||||
| Pi Agent Plugin | `pi-agent-plugin-checks.yml` | Push to main (`integrations/pi-agent-plugin/`), manual | tsc + vitest + tsup on Node 20, 22 |
|
||||
| DeepSeek Harness Plugin | `deepseek-plugin-checks.yml` | Push to main (`integrations/deepseek-plugin/`), manual | tsc + vitest + tsup on Node 20, 22 |
|
||||
| n8n Node | `n8n-nodes-mem0-checks.yml` | Push to main (`integrations/n8n-nodes-mem0/`), manual | ESLint + tsc build on Node 20 |
|
||||
| Zapier App | `zapier-mem0-checks.yml` | Push to main (`integrations/zapier-mem0/`), manual | tsc + `zapier validate` + offline unit tests on Node 22 |
|
||||
| mem0-strands | `mem0-strands-checks.yml` | Push to main (`integrations/mem0-strands/`), manual | Ruff + mypy + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||
| docs llms.txt | `docs-llms-txt-check.yml` | Manual | `docs/llms.txt` coverage |
|
||||
| GitHub Scripts | inline in `ci-gate.yml` | none | `node` over every `.github/scripts/*.test.js` |
|
||||
|
||||
Adding a 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` with a path filter under the `changes` job, a call job, and an entry in the gate job's `needs` list.
|
||||
|
||||
`GitHub Scripts` is the one row that is a plain job inside `ci-gate.yml` rather than a called workflow, because a reusable workflow wrapping two `node` invocations would be more file than test. It runs on the `github_scripts` filter, which covers `.github/scripts/**` plus every file those tests read: `pr-gate.yml`, `vouch-check-pr.yml`, `issue-labeler.yml`, and `VOUCHED.td`. Add a new `.github/scripts/*.test.js` and it is picked up with no wiring; make a test read a new file and that file belongs in the filter.
|
||||
|
||||
## Branch protection on `main`
|
||||
|
||||
A repository ruleset named `Main Branch Rule`, id `11813754`. It enforces squash-only merges, linear history, no deletion, no force-push, and one approving review. Two status checks belong in its `required_status_checks` rule:
|
||||
|
||||
| Context | Posted by | Why |
|
||||
|---------|-----------|-----|
|
||||
| `CI Gate` | `ci-gate.yml` | Aggregates every package pipeline |
|
||||
| `license/cla` | CLA Assistant | Proves the CLA is signed, not merely requested |
|
||||
|
||||
Editing the ruleset requires repo **admin**. `maintain` is not enough, and the API returns 404 rather than 403 in that case. Until `license/cla` is required, the claim in `CONTRIBUTING.md` that unsigned PRs are blocked from merging holds by convention only.
|
||||
|
||||
Requiring `CI Gate` also means fork PRs from first-time contributors cannot merge until a maintainer approves the workflow run. Those sit at `action_required`, which is intended behavior.
|
||||
|
||||
## CD: one router, many publishers
|
||||
|
||||
`release.yml` (**Release Router**) is the only workflow listening to `release: published`. It matches the tag prefix and dispatches the matching package workflow through `workflow_dispatch`, so one release produces exactly one routed run.
|
||||
|
||||
| Workflow | File | Tag prefix | Target |
|
||||
|----------|------|------------|--------|
|
||||
| Release Router | `release.yml` | all releases | dispatches the rows below |
|
||||
| Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) |
|
||||
| TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) |
|
||||
| Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) |
|
||||
| Node CLI | `cli-node-cd.yml` | `cli-node-v*` | npm (`@mem0/cli`) |
|
||||
| Vercel AI SDK | `vercel-ai-cd.yml` | `vercel-ai-v*` | npm (`@mem0/vercel-ai-provider`) |
|
||||
| OpenClaw | `openclaw-cd.yml` | `openclaw-v*` | npm (`@mem0/openclaw-mem0`) |
|
||||
| OpenCode Plugin | `opencode-plugin-cd.yml` | `opencode-v*` | npm (`@mem0/opencode-plugin`) |
|
||||
| Pi Agent Plugin | `pi-agent-plugin-cd.yml` | `pi-agent-v*` | npm (`@mem0/pi-agent-plugin`) |
|
||||
| DeepSeek Harness Plugin | `deepseek-plugin-cd.yml` | `deepseek-plugin-v*` | npm (`@mem0/deepseek-plugin`) |
|
||||
| n8n Node | `n8n-nodes-mem0-cd.yml` | `n8n-nodes-mem0-v*` | npm (`@mem0/n8n-nodes-mem0`) |
|
||||
| mem0-strands | `mem0-strands-cd.yml` | `mem0-strands-v*` | PyPI (`mem0-strands`) |
|
||||
|
||||
- Package CD workflows are `workflow_dispatch`-only, with `tag` and `prerelease` inputs. They check out and build the given tag.
|
||||
- All publishing uses **OIDC trusted publishing**. No tokens, no secrets.
|
||||
- Registry trusted-publisher settings are pinned to each package's own workflow **filename**. Renaming a CD workflow breaks publishing for that package.
|
||||
- First publish of a new npm package must be done manually. OIDC works from the second version onward.
|
||||
- To re-publish a release, do **not** delete and recreate the GitHub release. Dispatch the workflow directly: `gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>`.
|
||||
- The Zapier app deploys to Zapier's platform, not npm, so it is not in the router. Deploy with `gh workflow run zapier-mem0-cd.yml --ref main`.
|
||||
- Adding a package: add its CD workflow, then register its tag prefix in the `case` block in `release.yml`, keeping the bare `v*` arm last.
|
||||
|
||||
## Contribution gates
|
||||
|
||||
| Workflow | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| PR Gate | `pr-gate.yml` | Closes PRs that do not link an issue labeled `accepted`, and reopens them when that label arrives. Exempts members, bots, drafts, and docs-only changes. Never checks out PR code. |
|
||||
| Vouch (check PR) | `vouch-check-pr.yml` | Closes PRs from authors denounced in `VOUCHED.td`. Comments once on PRs from authors merely absent from it, and blocks nothing in that case. |
|
||||
| Vouch (manage list) | `vouch-manage-by-issue.yml` | Maintainers edit the trust list by commenting `!vouch @user`, `!denounce @user`, or `!unvouch @user` on any issue. Opens a PR against `VOUCHED.td` through a GitHub App token, for a maintainer to merge. |
|
||||
| Issue Labeler | `issue-labeler.yml` | Labels issues from the `component` field in the issue forms |
|
||||
| PR Labeler | `pr-labeler.yml` | Path-based labels, plus propagating labels from linked issues |
|
||||
| Stale Bot | `stale.yml` | Marks stale issues and PRs |
|
||||
| llms.txt Check | `docs-llms-txt-check.yml` | Blocks PRs touching `docs/**/*.mdx` when `docs/llms.txt` is out of sync |
|
||||
|
||||
`pr-gate.yml` and `vouch-check-pr.yml` use `pull_request_target`, which is required to label and close fork PRs. Neither checks out PR code and neither has a `run:` step, so there is no pwn-request or script-injection surface. Keep it that way: any future `run:` step in these files must never interpolate `github.event.*` text.
|
||||
|
||||
Both workflows exempt maintainers twice, and the second guard is the one that holds. `author_association` is rendered for the viewer, and a webhook payload has no privileged viewer: `MEMBER` needs the author's org membership to be **public**, `COLLABORATOR` needs a **direct** repository invite. An org member with private membership whose `maintain` comes through a team matches neither and arrives as `CONTRIBUTOR`, which is how PR #6948 was closed by its own author's gate. So the guard also skips any PR whose head branch lives in this repository (`head.repo.full_name == github.repository`). Pushing a branch here already requires write access and outside contributors always arrive from a fork, so that test means the same thing without depending on who is looking. Keep both: the `author_association` arm still covers members who work from their own fork.
|
||||
|
||||
`pr-gate.yml` carries two jobs whose `if:` conditions are deliberately disjoint. `gate` closes, and only ever runs on `opened`, `reopened`, and `ready_for_review`. `reopen` reopens, and only ever runs on `edited` or on `issues: labeled` with the `accepted` label. Nothing can both close and reopen on the same event, which is the property to preserve when editing either guard.
|
||||
|
||||
That split exists because the two halves of a gated PR's recovery arrive in either order. A maintainer usually labels the issue `accepted` at triage, before the author has linked it; sometimes the link lands first and the label follows. So `reopen` handles both directions. From `issues: labeled` it walks `closedByPullRequestsReferences` back to the pull requests that link the issue. From `edited` it takes the edited pull request directly. Both paths then apply the same four tests: the author is not denounced in `VOUCHED.td`, the PR is `CLOSED`, it links an issue labeled `accepted`, and it carries the `<!-- pr-gate -->` marker comment. Without the label path, a maintainer's label is inert. Without the `edited` path, an author who links the issue after it was labeled is stuck, since no other event fires.
|
||||
|
||||
The denounce test is what keeps the two gates from cancelling each other out. A denounced author whose PR also lacked an accepted issue was closed by both workflows, so it carries the `<!-- pr-gate -->` marker, and labeling the linked issue would otherwise reopen it. Vouch cannot undo that: reopening runs through `GITHUB_TOKEN`, which raises no events, so `vouch-check-pr.yml` never fires a second time. Reading the list here is the only place the check can live. It fails open like vouch does, warning and treating nobody as denounced if the file cannot be read, and it is the one piece of vouch semantics duplicated outside `vouch-check-pr.yml`, because `pr-gate.yml` never checks out the repository and so cannot import a shared parser. `.github/scripts/vouch-decision.test.js` covers the parsing and asserts `pr-gate.yml` still filters the list the same way.
|
||||
|
||||
`edited` must never reach the `gate` job. It fires on any title or description change, so when `gate` listened for it the gate re-judged pull requests that had been open for days and closed them the moment their author touched the description, which is what closed #6948. Rescuing on `edited` is safe for the same reason closing on it was not: the job can only move a PR from closed to open.
|
||||
|
||||
Reopening runs through `GITHUB_TOKEN`, which by design raises no further workflow events, so `gate` cannot bounce a freshly reopened PR straight back out.
|
||||
|
||||
The concurrency group is keyed on `github.event.action` as well as `github.event_name` and the number, and both keys carry weight. Without the event name, a maintainer applying `bug` right after `accepted` cancels the reopen mid-flight, since `cancel-in-progress` is on for `pull_request_target` and both label events would land in the same group. Without the action, `opened` and `edited` share a group on the same pull request, and an author who ticks a template checkbox in the seconds after opening cancels the run that was about to gate them: `gate` skips `edited` and `reopen` skips an open pull request, so the cancelled run is never replaced and the pull request stays ungated forever, since `opened` fires exactly once. Rapid successive edits still cancel each other, which is the dedup that was wanted.
|
||||
|
||||
The `edited` arm of `reopen` requires `github.event.pull_request.state == 'closed'`, so ordinary description edits on open pull requests do not start a runner.
|
||||
|
||||
Two known gaps, both mild. A PR that the gate closed, that someone reopened, and that a maintainer then closed deliberately still carries the marker, so labeling its issue reopens it again; a maintainer closes it once more. And an author who strips `Closes #<number>` out after passing keeps an open PR, which a reviewer sees anyway.
|
||||
|
||||
`GATE_EFFECTIVE_FROM` in `pr-gate.yml` is a `created_at` cutoff. `reopened` and `ready_for_review` still fire on PRs opened long before the gate existed, so without the cutoff part of the open backlog would be closed by a rule that did not exist when those PRs were filed. Set it to the actual merge date in UTC.
|
||||
|
||||
The gate's docs-only exemption covers `docs/` plus a named allowlist of four root files: `README.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and `SECURITY.md`. It is an allowlist rather than a rule about top-level markdown because the repository root also holds `AGENTS.md`, `CLAUDE.md`, and `LLM.md`, which are the instructions coding agents read before touching this codebase. Those are functional files that happen to be written in prose, and rewriting them is a change to behaviour, so they stay gated. Markdown nested anywhere else stays gated for the same reason: `skills/**/*.md` and everything under `.github/` are functional too. Adding a genuinely prose root file means adding it to `rootDocs` in `pr-gate.yml`.
|
||||
|
||||
`.github/scripts/pr-gate-docs-exemption.test.js` covers that predicate. It pulls the `rootDocs` and `isDocs` lines out of `pr-gate.yml` and evaluates them, so it exercises the shipped rule rather than a copy that could drift from it, and it pins `AGENTS.md`, `CLAUDE.md`, and `LLM.md` on the gated side along with `skills/**/*.md`, nested `.github/` files, and the empty file list. It only accepts those two declarations in a literal one-line form, so keep `rootDocs` a `Set` of quoted names and `isDocs` a single arrow expression.
|
||||
|
||||
The two contribution gates answer different questions and neither covers for the other. `pr-gate.yml` judges the change, and the `accepted` label is how a maintainer says yes to it. `vouch-check-pr.yml` judges the author, and `VOUCHED.td` is how a maintainer says no to one. A vouched author with no accepted issue is still closed by the gate; a denounced author with an accepted issue is still closed by vouch. Read either one as a backstop for the other and both get weakened.
|
||||
|
||||
Vouch enforces on the denounce axis only, through `require-vouch: false` with `auto-close: true`. That pair is not the obvious reading of either input, so the decision table from v1.5.0 (`vouch/github.nu` at pinned SHA `d66fa29`) is worth stating outright:
|
||||
|
||||
| Author | `status` | Effect |
|
||||
|---|---|---|
|
||||
| ends in `[bot]` | `skipped` | nothing |
|
||||
| collaborator with write or admin | `vouched` | nothing |
|
||||
| listed in `VOUCHED.td` | `vouched` | nothing |
|
||||
| listed as `-handle` | `closed` | action comments and closes |
|
||||
| absent from the file | `allowed` | workflow comments, nothing closed |
|
||||
|
||||
`require-vouch: true` would close every first-time contributor, which is the opposite of what a trust list is for: the funnel has to stay open or nobody ever earns a vouch. `auto-close: false` is the setting that looked safe and did nothing at all, since in v1.5.0 both the unvouched and the denounced branch return before posting anything, leaving only a line in the run log. That is why `!denounce` was decorative until this pair landed.
|
||||
|
||||
Only the `allowed` arm is ours: a `github-script` step posts the soft comment, keyed on a `<!-- vouch-check -->` marker so a reopen does not comment twice. The `closed` arm belongs to the action, message and all. Keeping the two arms disjoint is what stops a denounced author getting two comments, so if that step is ever re-keyed off `allowed`, check the overlap first.
|
||||
|
||||
`.github/scripts/vouch-decision.test.js` holds that table as a `decide()` function and asserts the workflow's `require-vouch`, `auto-close`, and comment-step gating still produce it, comment counts included. Be clear about what that does and does not prove. `decide()` is a **hand transcription** of `gh-check-pr`, read from `vouch/github.nu` at the pinned SHA; the test cannot run the action, so it cannot notice the action changing underneath it. Left alone it would agree with itself forever, which makes bumping the pinned SHA the one edit it would otherwise sail through. So it also asserts `vouch-check-pr.yml` still pins `PINNED_VOUCH_SHA`, and a bump fails it on purpose: re-read `gh-check-pr` at the new revision, correct `decide()` and the table above, then move the constant. CI runs it through the `GitHub Scripts` job on any change to the scripts or the files they read.
|
||||
|
||||
Failure is open by design. If the action cannot read `VOUCHED.td` it falls back to an empty list, every author reads as absent, and nobody is closed by an API hiccup.
|
||||
|
||||
`vouch-manage-by-issue.yml` runs with `merge-immediately: "false"`. The `Main Branch Rule` ruleset requires one approving review and has no bypass actors, so the action's immediate `PUT /pulls/{n}/merge` would return 405 and leave `VOUCHED.td` unchanged on `main`. The bot opens the PR, a maintainer merges it. Setting `pull-request: "false"` is not an alternative: the same ruleset blocks direct pushes.
|
||||
|
||||
That workflow also needs `VOUCH_APP_ID` and `VOUCH_APP_PRIVATE_KEY` repository secrets. Without them it fails at the token step before doing anything. `vouch-check-pr.yml` needs neither.
|
||||
|
||||
## Issue forms and templates
|
||||
|
||||
`ISSUE_TEMPLATE/*.yml` are GitHub issue **forms**, not markdown templates. Only forms support `required: true` and machine-parseable field ids. Blank issues are disabled in `config.yml`.
|
||||
|
||||
`issue-labeler.yml` reads only the `component` field id through `stefanbuck/github-issue-parser` and `redhat-plumbers-in-action/advanced-issue-labeler`, so adding new field ids is safe. Renaming `component` is not.
|
||||
|
||||
Current field ids:
|
||||
|
||||
| Form | Ids |
|
||||
|------|-----|
|
||||
| `bug_report.yml` | `component`, `description`, `verification`, `ai_assistance` |
|
||||
| `feature_request.yml` | `component`, `description`, `ai_assistance` |
|
||||
| `documentation_issue.yml` | `description`, `ai_assistance` |
|
||||
|
||||
## Trust list
|
||||
|
||||
`VOUCHED.td` is one GitHub username per line, `#` for comments. Seeded from every author with at least one merged PR in this repository, then filtered: accounts at or below a 16% merge rate across five or more attempts were dropped, since landing one change out of many is the signature of automated submission rather than contribution.
|
||||
|
||||
Vouch's only built-in exemptions are accounts ending in `[bot]` and repo collaborators with `write` or `admin`. **Organization membership alone is not one of them.** So `vouch-check-pr.yml` carries a job-level `if:` that skips the check for `OWNER`, `MEMBER`, and `COLLABORATOR` authors, the same exemption `pr-gate.yml` already applies. Org members are still listed in the file as a fallback, but the workflow guard is what actually holds.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
AGENTS.md
|
||||
@@ -51,3 +51,43 @@ body:
|
||||
- OS:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: verification
|
||||
attributes:
|
||||
label: How You Verified This
|
||||
description: We only take on bugs someone has actually reproduced. Show your work.
|
||||
value: |
|
||||
### What I Ran
|
||||
|
||||
The exact command or script, and where it ran.
|
||||
|
||||
### What I Saw
|
||||
|
||||
The real output, log line, or traceback. Paste it, do not describe it.
|
||||
|
||||
### Why This Is a Bug
|
||||
|
||||
What should have happened instead, and what says so: a docs link, a
|
||||
docstring, a test, or the code itself.
|
||||
|
||||
### What I Ruled Out
|
||||
|
||||
Anything you checked that turned out not to be the cause.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: ai_assistance
|
||||
attributes:
|
||||
label: AI Assistance
|
||||
description: >-
|
||||
This asks how the bug was found and confirmed, not how the text was
|
||||
written. Drafting the write-up with AI is fine. We ask because it tells
|
||||
us how much to trust the reproduction, not because it counts against you.
|
||||
options:
|
||||
- No AI involved
|
||||
- AI helped me find it, and I reproduced it myself afterwards
|
||||
- AI found and wrote this, and I have not reproduced it myself
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord Community
|
||||
- name: Question or general help
|
||||
url: https://discord.gg/6PzXDgEjG5
|
||||
about: Ask questions and discuss with the community
|
||||
about: Ask on Discord. The issue tracker is for bugs and accepted work only.
|
||||
- name: Documentation
|
||||
url: https://docs.mem0.ai
|
||||
about: Read the official mem0 documentation
|
||||
- name: Report a security vulnerability
|
||||
url: https://github.com/mem0ai/mem0/security/advisories/new
|
||||
about: Report privately through a security advisory. Never open a public issue.
|
||||
|
||||
@@ -21,3 +21,17 @@ body:
|
||||
How should the docs be improved?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: ai_assistance
|
||||
attributes:
|
||||
label: AI Assistance
|
||||
description: >-
|
||||
This asks how the problem was found, not how the text was written.
|
||||
Drafting the write-up with AI is fine.
|
||||
options:
|
||||
- No AI involved, I hit this reading the docs
|
||||
- AI-assisted, but I checked the page myself
|
||||
- AI found this, and I have not opened the page
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -36,3 +36,18 @@ body:
|
||||
Any workarounds you've tried or other approaches considered.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: ai_assistance
|
||||
attributes:
|
||||
label: AI Assistance
|
||||
description: >-
|
||||
This asks where the idea came from, not how the text was written.
|
||||
Drafting the write-up with AI is fine. A request you hit yourself while
|
||||
building something carries more weight than one a model suggested.
|
||||
options:
|
||||
- No AI involved, this is a need I hit myself
|
||||
- AI-assisted, but the need is mine
|
||||
- AI suggested this feature
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -14,6 +14,18 @@ Closes #<!-- issue number -->
|
||||
- [ ] Refactor (no functional changes)
|
||||
- [ ] Documentation update
|
||||
|
||||
## AI Assistance
|
||||
|
||||
<!-- This is about the code, not this description. Writing the description with AI is fine. -->
|
||||
|
||||
- [ ] No AI assistance
|
||||
- [ ] AI-assisted (autocomplete, or I asked a model questions while writing this)
|
||||
- [ ] AI-generated (an agent wrote most or all of this diff)
|
||||
|
||||
<!-- If you ticked either AI box, name the tool and what you checked yourself. -->
|
||||
|
||||
- [ ] **I can explain every line of this diff and how it interacts with the rest of the codebase, without asking an AI tool.**
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
<!-- If this is a breaking change, describe what breaks and the migration path. Delete this section if not applicable. -->
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
# The list of vouched (or denounced) users for this repository.
|
||||
#
|
||||
# A denounced user (prefixed with a minus) is blocked outright: their pull
|
||||
# requests are closed on sight, whatever they link. Being absent from this file
|
||||
# blocks nothing. An unvouched author gets one comment saying so and their pull
|
||||
# request is reviewed like anyone else's, because a first contribution has to
|
||||
# start somewhere. Vouching is how that comment stops.
|
||||
#
|
||||
# This list is about who, and it is the only thing that judges who. Whether a
|
||||
# change is wanted is a separate question, answered by the accepted label and
|
||||
# enforced by pr-gate.yml. Neither gate substitutes for the other: a vouched
|
||||
# author still needs an accepted issue, and a denounced author is turned away
|
||||
# even holding one.
|
||||
#
|
||||
# Vouch automatically allows two kinds of account without consulting this file:
|
||||
# accounts ending in [bot], and repo collaborators with write or admin
|
||||
# permission. Org membership on its own is NOT one of them, so
|
||||
# vouch-check-pr.yml skips the check for OWNER, MEMBER, and COLLABORATOR
|
||||
# authors, and for any branch pushed to this repository.
|
||||
#
|
||||
# Keep every mem0ai member listed below anyway. The author_association arm of
|
||||
# that guard is weaker than it looks: MEMBER needs the member's org membership
|
||||
# to be public and COLLABORATOR needs a direct repo invite, so a member with
|
||||
# private membership and a team-derived role reads as CONTRIBUTOR. Working from
|
||||
# a branch here covers them, working from their own fork leaves this file as
|
||||
# the only thing that does. A missing or miscased entry is a real gap.
|
||||
#
|
||||
# Syntax:
|
||||
# - One handle per line (without @), sorted alphabetically.
|
||||
# - Optionally specify platform: `platform:username` (e.g. `github:mitchellh`).
|
||||
# - To denounce a user, prefix with minus: `-username`.
|
||||
# - Optionally add a note after a space following the handle.
|
||||
#
|
||||
# Maintainers vouch by commenting "!vouch @username" on any issue, and denounce
|
||||
# with "!denounce @username". The bot commits the change back to this file.
|
||||
#
|
||||
# Seeded on 2026-08-12 from every author with at least one merged pull request,
|
||||
# then filtered: accounts with a merge rate at or below 16% across six or more
|
||||
# attempts were dropped, since landing one change out of many is the signature
|
||||
# of automated submission rather than contribution. Removal is not a ban. Any
|
||||
# maintainer can !vouch these accounts back in.
|
||||
1MikeMakuch
|
||||
aaishikdutta
|
||||
Aarkin7
|
||||
abdullahirfann
|
||||
AbdurNawaz
|
||||
abhay-codes07
|
||||
Abhineshhh
|
||||
ac12644
|
||||
acarbonetto
|
||||
adh-wonolo
|
||||
Aditya-Tripuraneni
|
||||
aesher9o1
|
||||
agumpandey
|
||||
ahnedeee
|
||||
ajmalmohad
|
||||
AkisAya
|
||||
akshat1423
|
||||
akshseh
|
||||
alessandropanzieri
|
||||
alohays
|
||||
aloktripathi1
|
||||
amahuli03
|
||||
amanagarwal042
|
||||
Ameysr
|
||||
amjadraza
|
||||
anantoj
|
||||
anchit-nishant
|
||||
andrewghlee
|
||||
andy-k-improving
|
||||
anifort
|
||||
anishesg
|
||||
AnkushMalaker
|
||||
AnnaSuSu
|
||||
anujshandillya
|
||||
ArchishmanSengupta
|
||||
Arsh-mem0
|
||||
ArthurHoward1
|
||||
aryankhanna475
|
||||
Ashu463
|
||||
atahanyild
|
||||
AtharvaJaiswal005
|
||||
atkinsh
|
||||
avp1598
|
||||
axelray-dev
|
||||
ayaangazali
|
||||
aymenkrifa
|
||||
barry166
|
||||
being-abhi
|
||||
berwinjoule
|
||||
BillionClaw
|
||||
bioshazard
|
||||
bisla
|
||||
bkidd1
|
||||
blino
|
||||
bmsvinci1729
|
||||
boss-mao
|
||||
Br1an67
|
||||
brucewkz
|
||||
cachho
|
||||
caifeizhi
|
||||
candidosales
|
||||
cclauss
|
||||
chaithanyak42
|
||||
chinnuabey
|
||||
ChiragArora31
|
||||
ChrisFloofyKitsune
|
||||
chrisqu777
|
||||
clementantonyk
|
||||
codexvn
|
||||
Colsrch
|
||||
CrepuscularIRIS
|
||||
ctxlong
|
||||
danielsiwiec
|
||||
darkhaniop
|
||||
davidatorres
|
||||
deshraj
|
||||
Dev-Khant
|
||||
Devan019
|
||||
deven298
|
||||
devYRPauli
|
||||
DhanushNehru
|
||||
DhilipBinny
|
||||
Dhravya
|
||||
dimigerontaki
|
||||
Diveyam-Mishra
|
||||
divyansh-1009
|
||||
Divyanshu9822
|
||||
dog-last
|
||||
DrJsPBs
|
||||
dtee1
|
||||
DumoeDss
|
||||
e-biswas
|
||||
Echo3ToEcho7
|
||||
eldar702
|
||||
eltociear
|
||||
EnzoFanAccount
|
||||
Esparon1
|
||||
Fahmid-Arman
|
||||
Failfail2603
|
||||
FarukhS52
|
||||
farzad528
|
||||
felipeavilis
|
||||
femto
|
||||
fengjikui
|
||||
fenilfaldu
|
||||
fileames
|
||||
Flyfoxs
|
||||
fmercurio
|
||||
FoliageOwO
|
||||
fran3cc
|
||||
frank-zsy
|
||||
frederikb96
|
||||
Freshield
|
||||
freya0926
|
||||
G26karthik
|
||||
gabe-l-hart
|
||||
gabrielstein-mem0
|
||||
gajazlikovac
|
||||
gasolin
|
||||
gaurav0107
|
||||
gauravagerwala
|
||||
Genarojrsanchez
|
||||
ghdcksgml1
|
||||
GingerMoon
|
||||
gmdorf
|
||||
golemus
|
||||
GongRzhe
|
||||
GopalGB
|
||||
Gyubin
|
||||
haarishmk26
|
||||
hackice20
|
||||
halanm
|
||||
hardik1408
|
||||
Harin329
|
||||
harshgupta-mem0
|
||||
harshpandit007
|
||||
hayescode
|
||||
hcsum
|
||||
he-yufeng
|
||||
heng-ah
|
||||
Hexecu
|
||||
Himanshu-Sangshetti
|
||||
hjlarry
|
||||
HowieG
|
||||
HrushiYadav
|
||||
HScarb
|
||||
huveewomg
|
||||
Hybirdss
|
||||
ianupamsingh
|
||||
IgnazioDS
|
||||
immuhammadfurqan
|
||||
into-the-night
|
||||
invincible04
|
||||
Itz-Antaripa
|
||||
ixchio
|
||||
Jaco-Ren
|
||||
Jai0401
|
||||
JainamShah-22
|
||||
Jainish-S
|
||||
jarediaz
|
||||
jeanibarz
|
||||
Jerry-Terrasse
|
||||
jessai2026
|
||||
jesse-c
|
||||
jfeng18
|
||||
jferrettiboke
|
||||
jjjojoj
|
||||
joaomdmoura
|
||||
JoeSL
|
||||
johnwlockwood
|
||||
jonasiwnl
|
||||
josephchancey
|
||||
juananpe
|
||||
juaneloDev
|
||||
junmo1215
|
||||
Jupiter363
|
||||
KapilM26
|
||||
karthik-indla
|
||||
KarthikeyaKollu
|
||||
kartik-mem0
|
||||
katarinasupe
|
||||
ketangangal
|
||||
kimnamu
|
||||
kindertheo
|
||||
kirex0
|
||||
kirklin
|
||||
kk2211
|
||||
kmitul
|
||||
koi646
|
||||
kratos0718
|
||||
krescent
|
||||
Krishnachaitanyakc
|
||||
kriszlazar
|
||||
KushagraB424
|
||||
l1anch1
|
||||
lamost423
|
||||
lan17
|
||||
LeonieFreisinger
|
||||
lh0x00
|
||||
limboinf
|
||||
liviaellen
|
||||
longway-code
|
||||
lsvishaal
|
||||
LuciAkirami
|
||||
lucifertrj
|
||||
lvpx
|
||||
ly-wang19
|
||||
maamalama
|
||||
maccuryj
|
||||
mae5357
|
||||
mahone3297
|
||||
Malhis
|
||||
maljazaery
|
||||
manganeseheptoxide
|
||||
manthanguptaa
|
||||
mark-watson
|
||||
Mark-Zeng
|
||||
markmbain
|
||||
matanco1
|
||||
mauricioalarcon
|
||||
maxvonhippel
|
||||
me-tusharchandra
|
||||
mezotv
|
||||
MgeeeeK
|
||||
mggger
|
||||
mgoulart
|
||||
microbluey
|
||||
mikejgray
|
||||
Mingxiangyu
|
||||
Mini256
|
||||
misrasaurabh1
|
||||
mjzcng
|
||||
mogith-pn
|
||||
morgoth9808
|
||||
moyueheng
|
||||
mrbusche
|
||||
Mrinank-Bhowmick
|
||||
muhammed-mamun
|
||||
MUZAMMILPERVAIZ
|
||||
mvanhorn
|
||||
naman09
|
||||
NavyaAlapati13
|
||||
neilbhutada
|
||||
NightClover-code
|
||||
nikhilsharma26500
|
||||
NILAY1556
|
||||
niv-hertz
|
||||
NoahStapp
|
||||
norrishuang
|
||||
OfficialAbhinavSingh
|
||||
officialasishkumar
|
||||
OjusWiZard
|
||||
okaditya84
|
||||
omahs
|
||||
OsamaNabih
|
||||
oskarrough
|
||||
p-tirth
|
||||
Padarn
|
||||
paipeline
|
||||
ParseDark
|
||||
parshvadaftari
|
||||
Parteeksachdeva
|
||||
parthshr370
|
||||
parzival418
|
||||
Paulie-Aditya
|
||||
paurushmittal
|
||||
pc9
|
||||
Pecunia201
|
||||
peterj
|
||||
pragnyanramtha
|
||||
PranavPuranik
|
||||
PrashantDixit0
|
||||
prateekchhikara
|
||||
prathameshagrawal
|
||||
pratikgajjar
|
||||
PratikRai0101
|
||||
Prikshit7766
|
||||
Prithvi1994
|
||||
QunBB
|
||||
rafid001
|
||||
raghavtyagii
|
||||
rahulsharmavishwakarma
|
||||
rajib76
|
||||
rakheesingh
|
||||
ranjithkumar8352
|
||||
Rayhanpatel
|
||||
reachAnushaKondam
|
||||
Real5K
|
||||
Rhythm-08
|
||||
richawo
|
||||
Rishiraj2594
|
||||
RitwijParmar
|
||||
RobinALG87
|
||||
rocke2020
|
||||
rodboev
|
||||
rohitgr7
|
||||
ron-42
|
||||
roshan-shaik-ml
|
||||
rst0070
|
||||
rudra717
|
||||
rudrajmehta-mem0
|
||||
rupamoraczen
|
||||
rupeshbansal
|
||||
ryanrozich
|
||||
SaharshPatel24
|
||||
sahilyadav902
|
||||
sahithreddy05
|
||||
SakshiSrivastava2024
|
||||
SamuelDevdas
|
||||
sarkarsaurabh27
|
||||
sdht0
|
||||
seetharam-rajagopal
|
||||
sergio-toro
|
||||
SerSamgy
|
||||
shafdev
|
||||
shashank42
|
||||
ShauryaaSharma
|
||||
Sheharyar570
|
||||
shenxiangzhuang
|
||||
ShivamMenda
|
||||
shlokkhemani
|
||||
shraderdm
|
||||
shrivastavanolo
|
||||
shubhampal123
|
||||
shuoli84
|
||||
sidmohanty11
|
||||
siroa
|
||||
slobodaapl
|
||||
soapun
|
||||
soumil-rathi
|
||||
spike-spiegel-21
|
||||
srishti-git1110
|
||||
SSDWGG
|
||||
sssserrano
|
||||
subhadip001
|
||||
subhajit20
|
||||
SudoAnirudh
|
||||
sukkritsharmaofficial
|
||||
sw8fbar
|
||||
swarnaprakash
|
||||
sxu75374
|
||||
SZemse
|
||||
taranjeet
|
||||
techcontributor
|
||||
tgabi333
|
||||
theagenticguy
|
||||
thomasgtaylor
|
||||
tomasonjo
|
||||
TommyZihao
|
||||
TruptiAgrawal
|
||||
turtletongue
|
||||
Tushar-kalsi
|
||||
Ukong0324
|
||||
umran666
|
||||
utkarsh240799
|
||||
UzairNaeem3
|
||||
V-Silpin
|
||||
vatsalrathod16
|
||||
vedant381
|
||||
veeceey
|
||||
vgvoleg
|
||||
VictorECDSA
|
||||
VikramIyer125
|
||||
Vir-8
|
||||
vsatyamuralikrishna
|
||||
vuonghuuhung
|
||||
WayneCao
|
||||
whysosaket
|
||||
wobushixiaoj
|
||||
xiangpingjiang
|
||||
XiaojuCH
|
||||
xu-xiang
|
||||
xyb
|
||||
yashikabadaya
|
||||
yashs33244
|
||||
ygorth
|
||||
youneshima
|
||||
ytkimirti
|
||||
YuriyTW
|
||||
YusukeJustinNakajima
|
||||
zaiddkhan
|
||||
zegerhoogeboom
|
||||
zinyando
|
||||
Zlo7
|
||||
Zncl2222
|
||||
zzaym
|
||||
@@ -0,0 +1,60 @@
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const gate = fs.readFileSync(path.join(__dirname, '..', 'workflows', 'pr-gate.yml'), 'utf8');
|
||||
|
||||
const rootDocsLine = gate.match(/^\s*(const rootDocs = new Set\(\['[\w.-]+'(?:, '[\w.-]+')*\]\);)\s*$/m);
|
||||
const isDocsLine = gate.match(/^\s*(const isDocs = \(\w+\) => [\w.'"()[\]\/, |&!=><+-]+;)\s*$/m);
|
||||
|
||||
assert.ok(
|
||||
rootDocsLine,
|
||||
'pr-gate.yml no longer declares rootDocs as a single-line Set of quoted filenames. ' +
|
||||
'This test evaluates that line to exercise the shipped predicate rather than a copy of it, ' +
|
||||
'and only accepts a literal shape, so widen the pattern deliberately or keep the declaration literal.',
|
||||
);
|
||||
assert.ok(
|
||||
isDocsLine,
|
||||
'pr-gate.yml no longer declares isDocs as a single-line arrow expression. ' +
|
||||
'This test evaluates that line to exercise the shipped predicate rather than a copy of it, ' +
|
||||
'and refuses anything with a statement body, so keep it an expression.',
|
||||
);
|
||||
|
||||
const isDocs = new Function(`${rootDocsLine[1]}\n${isDocsLine[1]}\nreturn isDocs;`)();
|
||||
|
||||
const exempt = (files) => files.length > 0 && files.every(isDocs);
|
||||
|
||||
const cases = [
|
||||
[['docs/a.mdx'], true],
|
||||
[['docs/platform/quickstart.mdx'], true],
|
||||
[['README.md'], true],
|
||||
[['CONTRIBUTING.md'], true],
|
||||
[['CODE_OF_CONDUCT.md'], true],
|
||||
[['SECURITY.md'], true],
|
||||
[['README.md', 'CONTRIBUTING.md', 'docs/x.mdx'], true],
|
||||
[['AGENTS.md'], false],
|
||||
[['CLAUDE.md'], false],
|
||||
[['LLM.md'], false],
|
||||
[['README.md', 'AGENTS.md'], false],
|
||||
[['README.md', 'mem0/memory/main.py'], false],
|
||||
[['skills/mem0/SKILL.md'], false],
|
||||
[['.github/AGENTS.md'], false],
|
||||
[['.github/workflows/ci.yml'], false],
|
||||
[['docs-site/index.md'], false],
|
||||
[[], false],
|
||||
];
|
||||
|
||||
let failures = 0;
|
||||
for (const [files, expected] of cases) {
|
||||
const actual = exempt(files);
|
||||
const label = files.length ? files.join(', ') : '(no files)';
|
||||
if (actual === expected) {
|
||||
console.log(`ok ${label} -> ${actual ? 'exempt' : 'gated'}`);
|
||||
} else {
|
||||
failures += 1;
|
||||
console.log(`FAIL ${label} -> ${actual ? 'exempt' : 'gated'}, expected ${expected ? 'exempt' : 'gated'}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(failures === 0 ? '\nPASS' : `\nFAIL (${failures} cases)`);
|
||||
process.exit(failures === 0 ? 0 : 1);
|
||||
@@ -0,0 +1,122 @@
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const workflowPath = path.join(__dirname, '..', 'workflows', 'vouch-check-pr.yml');
|
||||
const workflow = fs.readFileSync(workflowPath, 'utf8');
|
||||
|
||||
const PINNED_VOUCH_SHA = 'd66fa29a64600490892131ad87597c30c91fcac4';
|
||||
|
||||
assert.ok(
|
||||
workflow.includes(`mitchellh/vouch/action/check-pr@${PINNED_VOUCH_SHA}`),
|
||||
`decide() below is a hand transcription of gh-check-pr from vouch/github.nu at ${PINNED_VOUCH_SHA} (v1.5.0). ` +
|
||||
'It reads the action, it does not run it, so on its own it agrees with itself whatever the action does. ' +
|
||||
'vouch-check-pr.yml now pins a different revision: re-read gh-check-pr there, update decide() and the ' +
|
||||
'decision table in .github/AGENTS.md to match it, then set PINNED_VOUCH_SHA to the new SHA.',
|
||||
);
|
||||
|
||||
const actionDefaults = { 'require-vouch': true, 'auto-close': false };
|
||||
|
||||
const booleanInput = (name) => {
|
||||
const match = workflow.match(new RegExp(`^\\s+${name}:\\s*"?(true|false)"?\\s*$`, 'm'));
|
||||
return match ? match[1] === 'true' : actionDefaults[name];
|
||||
};
|
||||
|
||||
const requireVouch = booleanInput('require-vouch');
|
||||
const autoClose = booleanInput('auto-close');
|
||||
|
||||
const commentedStatus = (() => {
|
||||
const match = workflow.match(/steps\.vouch\.outputs\.status == '(\w+)'/);
|
||||
assert.ok(match, 'the follow-up comment step is not keyed on a vouch status');
|
||||
return match[1];
|
||||
})();
|
||||
|
||||
const decide = (author) => {
|
||||
if (author === 'bot') return { status: 'skipped', closed: false, actionComments: false };
|
||||
if (author === 'collaborator' || author === 'vouched') {
|
||||
return { status: 'vouched', closed: false, actionComments: false };
|
||||
}
|
||||
if (author === 'denounced') {
|
||||
if (!autoClose) return { status: 'closed', closed: false, actionComments: false };
|
||||
return { status: 'closed', closed: true, actionComments: true };
|
||||
}
|
||||
if (!requireVouch) return { status: 'allowed', closed: false, actionComments: false };
|
||||
if (!autoClose) return { status: 'closed', closed: false, actionComments: false };
|
||||
return { status: 'closed', closed: true, actionComments: true };
|
||||
};
|
||||
|
||||
const outcome = (author) => {
|
||||
const result = decide(author);
|
||||
return { ...result, workflowComments: result.status === commentedStatus };
|
||||
};
|
||||
|
||||
const cases = [
|
||||
{ author: 'bot', closed: false, comments: 0 },
|
||||
{ author: 'collaborator', closed: false, comments: 0 },
|
||||
{ author: 'vouched', closed: false, comments: 0 },
|
||||
{ author: 'unvouched', closed: false, comments: 1 },
|
||||
{ author: 'denounced', closed: true, comments: 1 },
|
||||
];
|
||||
|
||||
let failures = 0;
|
||||
for (const expected of cases) {
|
||||
const actual = outcome(expected.author);
|
||||
const comments = Number(actual.actionComments) + Number(actual.workflowComments);
|
||||
try {
|
||||
assert.strictEqual(actual.closed, expected.closed, `${expected.author}: closed`);
|
||||
assert.strictEqual(comments, expected.comments, `${expected.author}: comment count`);
|
||||
console.log(`ok ${expected.author} -> ${actual.status}, closed=${actual.closed}, comments=${comments}`);
|
||||
} catch (error) {
|
||||
failures += 1;
|
||||
console.log(`FAIL ${expected.author} -> ${actual.status}, closed=${actual.closed}, comments=${comments}`);
|
||||
console.log(` ${error.message}: expected ${JSON.stringify(expected)}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nvouch@${PINNED_VOUCH_SHA.slice(0, 7)} require-vouch=${requireVouch} auto-close=${autoClose} comment-on=${commentedStatus}`);
|
||||
|
||||
const parseDenounced = (contents) => new Set(contents
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.startsWith('-'))
|
||||
.map((line) => line.slice(1).split(/\s+/)[0].split(':').pop().toLowerCase())
|
||||
.filter(Boolean));
|
||||
|
||||
const gate = fs.readFileSync(path.join(__dirname, '..', 'workflows', 'pr-gate.yml'), 'utf8');
|
||||
assert.ok(
|
||||
gate.includes(".filter((line) => line.startsWith('-'))"),
|
||||
'pr-gate.yml no longer parses the denounce list the way this test does',
|
||||
);
|
||||
|
||||
const vouched = fs.readFileSync(path.join(__dirname, '..', 'VOUCHED.td'), 'utf8');
|
||||
const denouncedNow = parseDenounced(vouched);
|
||||
const sample = parseDenounced([
|
||||
'# -notacomment is a comment line',
|
||||
'-SpamBot seeded 2026-08-12',
|
||||
'-github:OtherSpammer',
|
||||
'realcontributor',
|
||||
'',
|
||||
].join('\n'));
|
||||
|
||||
let parseFailures = 0;
|
||||
for (const [label, actual, expected] of [
|
||||
['denounce entry, with note', sample.has('spambot'), true],
|
||||
['denounce entry, platform prefixed', sample.has('otherspammer'), true],
|
||||
['comment line is not an entry', sample.has('notacomment'), false],
|
||||
['vouched entry is not denounced', sample.has('realcontributor'), false],
|
||||
['live file parses without throwing', denouncedNow instanceof Set, true],
|
||||
]) {
|
||||
try {
|
||||
assert.strictEqual(actual, expected, label);
|
||||
console.log(`ok ${label}`);
|
||||
} catch (error) {
|
||||
parseFailures += 1;
|
||||
console.log(`FAIL ${label}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`denounced in VOUCHED.td: ${denouncedNow.size}`);
|
||||
|
||||
const total = failures + parseFailures;
|
||||
console.log(total === 0 ? 'PASS' : `FAIL (${total} assertions)`);
|
||||
process.exit(total === 0 ? 0 : 1);
|
||||
@@ -0,0 +1,97 @@
|
||||
name: Agent Plugins Python Checks
|
||||
|
||||
# Python runtime, adapters, generated bundles, and portable plugin validation.
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/agent-plugin-core/**'
|
||||
- '!integrations/agent-plugin-core/typescript/**'
|
||||
- 'integrations/mem0-agent-plugin/**'
|
||||
- 'integrations/claude-code-plugin/**'
|
||||
- 'integrations/cursor-plugin/**'
|
||||
- 'integrations/codex-plugin/**'
|
||||
- 'integrations/kimi-plugin/**'
|
||||
- 'integrations/antigravity-plugin/**'
|
||||
- 'marketplace.json'
|
||||
- '.agents/plugins/marketplace.json'
|
||||
- '.claude-plugin/marketplace.json'
|
||||
- '.codex-plugin/marketplace.json'
|
||||
- '.cursor-plugin/marketplace.json'
|
||||
- '.kimi-plugin/marketplace.json'
|
||||
- '.github/workflows/agent-plugins-python-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install runtime test tooling
|
||||
if: matrix.python-version == '3.10'
|
||||
run: pip install pytest
|
||||
|
||||
- name: Install build and test tooling
|
||||
if: matrix.python-version != '3.10'
|
||||
run: pip install pytest ruff -r integrations/agent-plugin-core/requirements-dev.txt
|
||||
|
||||
- name: Check Python runtime compatibility
|
||||
run: >-
|
||||
python3 -m compileall -q
|
||||
integrations/agent-plugin-core/python
|
||||
integrations/claude-code-plugin/adapters
|
||||
integrations/cursor-plugin/hooks
|
||||
integrations/codex-plugin/hooks
|
||||
integrations/kimi-plugin/hooks
|
||||
integrations/antigravity-plugin/hooks
|
||||
|
||||
- name: Lint
|
||||
if: matrix.python-version == '3.12'
|
||||
run: >-
|
||||
python3 -m ruff check
|
||||
integrations/agent-plugin-core
|
||||
integrations/claude-code-plugin
|
||||
integrations/cursor-plugin
|
||||
integrations/codex-plugin
|
||||
integrations/kimi-plugin
|
||||
integrations/antigravity-plugin
|
||||
|
||||
- name: Verify installable plugins are current
|
||||
if: matrix.python-version == '3.12'
|
||||
run: |
|
||||
for host in claude-code cursor codex kimi antigravity; do
|
||||
python3 integrations/agent-plugin-core/build/build.py "$host" --kind native --check
|
||||
done
|
||||
python3 integrations/agent-plugin-core/build/build.py mem0-agent-plugin --kind portable --check
|
||||
|
||||
- name: Run Python 3.10 runtime tests
|
||||
if: matrix.python-version == '3.10'
|
||||
run: >-
|
||||
python3 -m pytest -q
|
||||
integrations/claude-code-plugin/tests/test_memory_core.py
|
||||
integrations/claude-code-plugin/tests/test_telemetry.py
|
||||
|
||||
- name: Run full tests
|
||||
if: matrix.python-version != '3.10'
|
||||
run: >-
|
||||
python3 -m pytest -q
|
||||
integrations/agent-plugin-core/tests
|
||||
integrations/claude-code-plugin/tests
|
||||
integrations/cursor-plugin/tests
|
||||
integrations/codex-plugin/tests
|
||||
integrations/kimi-plugin/tests
|
||||
integrations/antigravity-plugin/tests
|
||||
--ignore=integrations/claude-code-plugin/tests/integration
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Agent Plugins TypeScript Checks
|
||||
|
||||
# Shared TypeScript runtime checks. Each consuming integration keeps its own
|
||||
# build workflow, which is also triggered when this shared core changes.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/agent-plugins-typescript-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/agent-plugin-core/typescript/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: integrations/agent-plugin-core/typescript
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Type check
|
||||
working-directory: integrations/agent-plugin-core/typescript
|
||||
run: pnpm typecheck
|
||||
|
||||
- name: Run tests
|
||||
working-directory: integrations/agent-plugin-core/typescript
|
||||
run: pnpm test
|
||||
@@ -38,12 +38,16 @@ jobs:
|
||||
cli_python: ${{ steps.filter.outputs.cli_python }}
|
||||
cli_node: ${{ steps.filter.outputs.cli_node }}
|
||||
openclaw: ${{ steps.filter.outputs.openclaw }}
|
||||
mem0_plugin: ${{ steps.filter.outputs.mem0_plugin }}
|
||||
agent_plugins_python: ${{ steps.filter.outputs.agent_plugins_python }}
|
||||
agent_plugins_typescript: ${{ steps.filter.outputs.agent_plugins_typescript }}
|
||||
opencode_plugin: ${{ steps.filter.outputs.opencode_plugin }}
|
||||
pi_agent_plugin: ${{ steps.filter.outputs.pi_agent_plugin }}
|
||||
deepseek_plugin: ${{ steps.filter.outputs.deepseek_plugin }}
|
||||
n8n_nodes_mem0: ${{ steps.filter.outputs.n8n_nodes_mem0 }}
|
||||
zapier_mem0: ${{ steps.filter.outputs.zapier_mem0 }}
|
||||
mem0_strands: ${{ steps.filter.outputs.mem0_strands }}
|
||||
docs_llms_txt: ${{ steps.filter.outputs.docs_llms_txt }}
|
||||
github_scripts: ${{ steps.filter.outputs.github_scripts }}
|
||||
steps:
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
@@ -72,21 +76,45 @@ jobs:
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
openclaw:
|
||||
- 'integrations/openclaw/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
mem0_plugin:
|
||||
- 'integrations/mem0-plugin/**'
|
||||
- '!integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/mem0-plugin-checks.yml'
|
||||
agent_plugins_python:
|
||||
- 'integrations/agent-plugin-core/**'
|
||||
- '!integrations/agent-plugin-core/typescript/**'
|
||||
- 'integrations/mem0-agent-plugin/**'
|
||||
- 'integrations/claude-code-plugin/**'
|
||||
- 'integrations/cursor-plugin/**'
|
||||
- 'integrations/codex-plugin/**'
|
||||
- 'integrations/kimi-plugin/**'
|
||||
- 'integrations/antigravity-plugin/**'
|
||||
- 'marketplace.json'
|
||||
- '.agents/plugins/marketplace.json'
|
||||
- '.claude-plugin/marketplace.json'
|
||||
- '.codex-plugin/marketplace.json'
|
||||
- '.cursor-plugin/marketplace.json'
|
||||
- '.kimi-plugin/marketplace.json'
|
||||
- '.github/workflows/agent-plugins-python-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
agent_plugins_typescript:
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/agent-plugins-typescript-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
opencode_plugin:
|
||||
- 'integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- 'integrations/opencode-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/opencode-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
pi_agent_plugin:
|
||||
- 'integrations/pi-agent-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
deepseek_plugin:
|
||||
- 'integrations/deepseek-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/deepseek-plugin-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
n8n_nodes_mem0:
|
||||
- 'integrations/n8n-nodes-mem0/**'
|
||||
- '.github/workflows/n8n-nodes-mem0-checks.yml'
|
||||
@@ -94,6 +122,10 @@ jobs:
|
||||
- 'integrations/zapier-mem0/**'
|
||||
- '.github/workflows/zapier-mem0-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
mem0_strands:
|
||||
- 'integrations/mem0-strands/**'
|
||||
- '.github/workflows/mem0-strands-checks.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
docs_llms_txt:
|
||||
- 'docs/**/*.mdx'
|
||||
- 'docs/llms.txt'
|
||||
@@ -101,6 +133,13 @@ jobs:
|
||||
- 'scripts/llms-txt-ignore.txt'
|
||||
- '.github/workflows/docs-llms-txt-check.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
github_scripts:
|
||||
- '.github/scripts/**'
|
||||
- '.github/VOUCHED.td'
|
||||
- '.github/workflows/pr-gate.yml'
|
||||
- '.github/workflows/vouch-check-pr.yml'
|
||||
- '.github/workflows/issue-labeler.yml'
|
||||
- '.github/workflows/ci-gate.yml'
|
||||
|
||||
python-sdk:
|
||||
name: Python SDK
|
||||
@@ -137,11 +176,17 @@ jobs:
|
||||
uses: ./.github/workflows/openclaw-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
mem0-plugin:
|
||||
name: Mem0 Plugin
|
||||
agent-plugins-python:
|
||||
name: Agent Plugins Python
|
||||
needs: changes
|
||||
if: needs.changes.outputs.mem0_plugin == 'true'
|
||||
uses: ./.github/workflows/mem0-plugin-checks.yml
|
||||
if: needs.changes.outputs.agent_plugins_python == 'true'
|
||||
uses: ./.github/workflows/agent-plugins-python-checks.yml
|
||||
|
||||
agent-plugins-typescript:
|
||||
name: Agent Plugins TypeScript
|
||||
needs: changes
|
||||
if: needs.changes.outputs.agent_plugins_typescript == 'true'
|
||||
uses: ./.github/workflows/agent-plugins-typescript-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
opencode-plugin:
|
||||
@@ -158,6 +203,13 @@ jobs:
|
||||
uses: ./.github/workflows/pi-agent-plugin-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
deepseek-plugin:
|
||||
name: DeepSeek Harness Plugin
|
||||
needs: changes
|
||||
if: needs.changes.outputs.deepseek_plugin == 'true'
|
||||
uses: ./.github/workflows/deepseek-plugin-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
n8n-nodes-mem0:
|
||||
name: n8n Node
|
||||
needs: changes
|
||||
@@ -170,6 +222,13 @@ jobs:
|
||||
uses: ./.github/workflows/zapier-mem0-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
mem0-strands:
|
||||
name: mem0-strands
|
||||
needs: changes
|
||||
if: needs.changes.outputs.mem0_strands == 'true'
|
||||
uses: ./.github/workflows/mem0-strands-checks.yml
|
||||
secrets: inherit
|
||||
|
||||
docs-llms-txt:
|
||||
name: docs llms.txt
|
||||
needs: changes
|
||||
@@ -177,6 +236,24 @@ jobs:
|
||||
uses: ./.github/workflows/docs-llms-txt-check.yml
|
||||
secrets: inherit
|
||||
|
||||
github-scripts:
|
||||
name: GitHub Scripts
|
||||
needs: changes
|
||||
if: needs.changes.outputs.github_scripts == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Run .github/scripts tests
|
||||
run: |
|
||||
for test in .github/scripts/*.test.js; do
|
||||
echo "::group::$test"
|
||||
node "$test"
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
gate:
|
||||
name: CI Gate
|
||||
needs:
|
||||
@@ -186,12 +263,16 @@ jobs:
|
||||
- cli-python
|
||||
- cli-node
|
||||
- openclaw
|
||||
- mem0-plugin
|
||||
- agent-plugins-python
|
||||
- agent-plugins-typescript
|
||||
- opencode-plugin
|
||||
- pi-agent-plugin
|
||||
- deepseek-plugin
|
||||
- n8n-nodes-mem0
|
||||
- zapier-mem0
|
||||
- mem0-strands
|
||||
- docs-llms-txt
|
||||
- github-scripts
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
}
|
||||
|
||||
base_version=$(git show "$BASE_SHA:pyproject.toml" 2>/dev/null | extract_version || echo "")
|
||||
head_version=$(extract_version < pyproject.toml)
|
||||
head_version=$(git show "$HEAD_SHA:pyproject.toml" | extract_version)
|
||||
|
||||
echo "Base version: ${base_version:-<unknown>}"
|
||||
echo "Head version: $head_version"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Publish @mem0/deepseek-plugin 📦 to npm
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# deepseek-plugin-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. deepseek-plugin-v0.1.1)'
|
||||
required: true
|
||||
type: string
|
||||
prerelease:
|
||||
description: 'Publish under the version preid dist-tag instead of latest'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
name: Build and publish @mem0/deepseek-plugin 📦 to npm
|
||||
if: startsWith(inputs.tag, 'deepseek-plugin-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/deepseek-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/deepseek-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
if [ "${{ inputs.prerelease }}" = "true" ]; then
|
||||
PREID=$(node -p "require('./package.json').version.split('-')[1].split('.')[0]")
|
||||
npx npm@latest publish --provenance --access public --tag "$PREID"
|
||||
else
|
||||
npx npm@latest publish --provenance --access public
|
||||
fi
|
||||
@@ -0,0 +1,89 @@
|
||||
name: deepseek-plugin checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/deepseek-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/deepseek-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/deepseek-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/deepseek-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Type check
|
||||
run: cd integrations/deepseek-plugin && pnpm exec tsc --noEmit
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20, 22]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/deepseek-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/deepseek-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
run: cd integrations/deepseek-plugin && pnpm exec vitest run
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: integrations/deepseek-plugin/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
run: cd integrations/deepseek-plugin && pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: cd integrations/deepseek-plugin && pnpm build
|
||||
|
||||
- name: Verify package artifact
|
||||
run: python3 integrations/agent-plugin-core/conformance/artifacts.py deepseek
|
||||
@@ -1,58 +0,0 @@
|
||||
name: Mem0 Plugin Checks
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
#
|
||||
# Covers the Python plugin (scripts/ + tests/). The nested .opencode-plugin/
|
||||
# is a separate package with its own workflow (opencode-plugin-checks.yml).
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/mem0-plugin/**'
|
||||
- '!integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- '.github/workflows/mem0-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
pip install -r requirements.txt
|
||||
pip install pytest
|
||||
|
||||
- name: Verify hook entry points are executable
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
missing=$(find scripts -name '*.sh' ! -name '_*' ! -perm -u+x -print)
|
||||
if [ -n "$missing" ]; then
|
||||
echo "Hook entry points must be executable:"
|
||||
echo "$missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check hook manifests are valid JSON
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: |
|
||||
for f in plugin.json mcp_config.json hooks.json hooks/*.json; do
|
||||
jq empty "$f" || (echo "Invalid JSON: $f" && exit 1)
|
||||
done
|
||||
|
||||
- name: Run tests
|
||||
working-directory: integrations/mem0-plugin
|
||||
run: pytest -q
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Publish mem0-strands 🐍 distribution 📦 to PyPI
|
||||
|
||||
# Dispatched by release.yml (Release Router) when a release tagged
|
||||
# mem0-strands-v* is published. Can also be dispatched manually to re-publish
|
||||
# a tag. Publishing uses PyPI Trusted Publishing (OIDC), so no API token is
|
||||
# stored; the `mem0-strands` PyPI project must have a trusted publisher
|
||||
# configured for mem0ai/mem0 + this workflow.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag to build and publish (e.g. mem0-strands-v0.1.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:
|
||||
build-n-publish:
|
||||
name: Build and publish mem0-strands 📦 to PyPI
|
||||
if: startsWith(inputs.tag, 'mem0-strands-v')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/mem0-strands/python
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.tag }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install Hatch
|
||||
run: pip install hatch
|
||||
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: hatch build --clean
|
||||
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
packages-dir: integrations/mem0-strands/python/dist/
|
||||
@@ -0,0 +1,82 @@
|
||||
name: mem0-strands CI
|
||||
|
||||
# On PRs this is invoked by ci-gate.yml (the single required check);
|
||||
# push-to-main and manual runs remain standalone.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/mem0-strands/**'
|
||||
- '.github/workflows/mem0-strands-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dev dependencies
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: pip install -e ".[dev]"
|
||||
|
||||
- name: Lint with ruff
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: ruff check .
|
||||
|
||||
- name: Check formatting
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: ruff format --check .
|
||||
|
||||
- name: Type-check with mypy
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: mypy src
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11", "3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dev dependencies
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: pip install -e ".[dev]"
|
||||
|
||||
- name: Run tests
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: pytest
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install Hatch
|
||||
run: pip install hatch
|
||||
|
||||
- name: Build
|
||||
working-directory: integrations/mem0-strands/python
|
||||
run: hatch build --clean
|
||||
|
||||
- name: Verify dist output
|
||||
run: |
|
||||
ls integrations/mem0-strands/python/dist/*.whl || (echo "Wheel file missing" && exit 1)
|
||||
ls integrations/mem0-strands/python/dist/*.tar.gz || (echo "Source dist missing" && exit 1)
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/openclaw/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/openclaw-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
@@ -93,7 +94,5 @@ jobs:
|
||||
- name: Build
|
||||
run: cd integrations/openclaw && pnpm build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f integrations/openclaw/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
test -f integrations/openclaw/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
|
||||
- name: Verify package artifact
|
||||
run: python3 integrations/agent-plugin-core/conformance/artifacts.py openclaw
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
id-token: write
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/mem0-plugin/.opencode-plugin
|
||||
working-directory: integrations/opencode-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -7,7 +7,8 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/mem0-plugin/.opencode-plugin/**'
|
||||
- 'integrations/opencode-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/opencode-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
@@ -16,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: integrations/mem0-plugin/.opencode-plugin
|
||||
working-directory: integrations/opencode-plugin
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -31,9 +32,12 @@ jobs:
|
||||
- name: Type check
|
||||
run: bun run type-check
|
||||
|
||||
- name: Test
|
||||
run: bun test
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
- name: Verify package artifact
|
||||
working-directory: .
|
||||
run: python3 integrations/agent-plugin-core/conformance/artifacts.py opencode
|
||||
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'integrations/pi-agent-plugin/**'
|
||||
- 'integrations/agent-plugin-core/typescript/**'
|
||||
- '.github/workflows/pi-agent-plugin-checks.yml'
|
||||
workflow_call:
|
||||
|
||||
@@ -84,9 +85,5 @@ jobs:
|
||||
- name: Build
|
||||
run: cd integrations/pi-agent-plugin && pnpm build
|
||||
|
||||
- name: Verify dist output exists
|
||||
run: |
|
||||
test -f integrations/pi-agent-plugin/dist/index.js || (echo "Build output missing: dist/index.js" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/index.d.ts || (echo "Build output missing: dist/index.d.ts" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/entry.js || (echo "Build output missing: dist/entry.js" && exit 1)
|
||||
test -f integrations/pi-agent-plugin/dist/entry.d.ts || (echo "Build output missing: dist/entry.d.ts" && exit 1)
|
||||
- name: Verify package artifact
|
||||
run: python3 integrations/agent-plugin-core/conformance/artifacts.py pi-agent
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
name: PR Gate
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, ready_for_review, edited]
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
concurrency:
|
||||
group: pr-gate-${{ github.event_name }}-${{ github.event.action }}-${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request_target' }}
|
||||
|
||||
env:
|
||||
GATE_EFFECTIVE_FROM: '2026-08-12T00:00:00Z'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: read
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
if: >-
|
||||
github.event_name == 'pull_request_target' &&
|
||||
github.event.action != 'edited' &&
|
||||
github.event.pull_request.draft == false &&
|
||||
github.event.pull_request.user.type != 'Bot' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
!contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
const effectiveFrom = process.env.GATE_EFFECTIVE_FROM;
|
||||
if (effectiveFrom && Date.parse(pr.created_at) < Date.parse(effectiveFrom)) {
|
||||
core.info(`Opened ${pr.created_at}, before the gate took effect ${effectiveFrom}. Skipped.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: current } = await github.rest.pulls.get({
|
||||
owner, repo, pull_number: pr.number,
|
||||
});
|
||||
if (current.state !== 'open') {
|
||||
core.info(`#${pr.number} is already ${current.state}. Skipped.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner, repo, pull_number: pr.number, per_page: 100,
|
||||
});
|
||||
const rootDocs = new Set(['README.md', 'CONTRIBUTING.md', 'CODE_OF_CONDUCT.md', 'SECURITY.md']);
|
||||
const isDocs = (filename) => filename.startsWith('docs/') || rootDocs.has(filename);
|
||||
if (files.length > 0 && files.every((file) => isDocs(file.filename))) {
|
||||
core.info('Docs-only PR, gate skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
const { repository } = await github.graphql(
|
||||
`query ($owner: String!, $repo: String!, $number: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
pullRequest(number: $number) {
|
||||
closingIssuesReferences(first: 20) {
|
||||
nodes { number labels(first: 50) { nodes { name } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ owner, repo, number: pr.number },
|
||||
);
|
||||
|
||||
const accepted = repository.pullRequest.closingIssuesReferences.nodes
|
||||
.filter((issue) => issue.labels.nodes.some((label) => label.name === 'accepted'))
|
||||
.map((issue) => issue.number);
|
||||
|
||||
if (accepted.length > 0) {
|
||||
core.info(`Accepted issue linked: #${accepted.join(', #')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const body = [
|
||||
'<!-- pr-gate -->',
|
||||
'Thanks for taking the time to open this.',
|
||||
'',
|
||||
'We only review pull requests that fix an issue we have already agreed to take on, so this one is closed for now.',
|
||||
'**Closed does not mean rejected.** It means it is not in the queue yet, and reopening takes about a minute.',
|
||||
'',
|
||||
'To get it reviewed:',
|
||||
'',
|
||||
'1. Make sure an issue describes the problem, with the version you are on, a runnable reproduction, and the real output or traceback you saw.',
|
||||
'2. Link it from this pull request description with `Closes #<number>`.',
|
||||
'3. Ask a maintainer to label that issue `accepted`. This pull request reopens by itself when they do.',
|
||||
'',
|
||||
'Issue already labeled `accepted`? Just add `Closes #<number>` to the description. That reopens this too.',
|
||||
'',
|
||||
'Documentation-only changes skip this gate entirely.',
|
||||
'',
|
||||
'See [CONTRIBUTING.md](https://github.com/mem0ai/mem0/blob/main/CONTRIBUTING.md) for the full policy.',
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: pr.number, body,
|
||||
});
|
||||
await github.rest.pulls.update({
|
||||
owner, repo, pull_number: pr.number, state: 'closed',
|
||||
});
|
||||
core.info(`Closed #${pr.number}: no accepted issue linked`);
|
||||
|
||||
reopen:
|
||||
if: >-
|
||||
(github.event_name == 'issues' && github.event.label.name == 'accepted') ||
|
||||
(github.event.action == 'edited' && github.event.pull_request.state == 'closed')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const marker = '<!-- pr-gate -->';
|
||||
|
||||
const denounced = await (async () => {
|
||||
try {
|
||||
const { data } = await github.rest.repos.getContent({
|
||||
owner, repo, path: '.github/VOUCHED.td',
|
||||
ref: context.payload.repository.default_branch,
|
||||
});
|
||||
return new Set(Buffer.from(data.content, 'base64').toString('utf8')
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.startsWith('-'))
|
||||
.map((line) => line.slice(1).split(/\s+/)[0].split(':').pop().toLowerCase())
|
||||
.filter(Boolean));
|
||||
} catch (error) {
|
||||
core.warning(`Could not read VOUCHED.td, treating nobody as denounced: ${error.message}`);
|
||||
return new Set();
|
||||
}
|
||||
})();
|
||||
|
||||
const isReopenable = async (number) => {
|
||||
const { repository } = await github.graphql(
|
||||
`query ($owner: String!, $repo: String!, $number: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
pullRequest(number: $number) {
|
||||
state
|
||||
author { login }
|
||||
closingIssuesReferences(first: 20) {
|
||||
nodes { labels(first: 50) { nodes { name } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ owner, repo, number },
|
||||
);
|
||||
const pullRequest = repository.pullRequest;
|
||||
if (denounced.has(pullRequest.author?.login?.toLowerCase())) {
|
||||
core.info(`#${number} is from a denounced author. Vouch outranks this gate.`);
|
||||
return false;
|
||||
}
|
||||
return pullRequest.state === 'CLOSED' &&
|
||||
pullRequest.closingIssuesReferences.nodes.some((issue) =>
|
||||
issue.labels.nodes.some((label) => label.name === 'accepted'));
|
||||
};
|
||||
|
||||
let candidates;
|
||||
if (context.eventName === 'issues') {
|
||||
const { repository } = await github.graphql(
|
||||
`query ($owner: String!, $repo: String!, $number: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
issue(number: $number) {
|
||||
closedByPullRequestsReferences(first: 20, includeClosedPrs: true) {
|
||||
nodes { number }
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{ owner, repo, number: context.payload.issue.number },
|
||||
);
|
||||
candidates = repository.issue.closedByPullRequestsReferences.nodes.map((pr) => pr.number);
|
||||
} else {
|
||||
candidates = [context.payload.pull_request.number];
|
||||
}
|
||||
|
||||
for (const number of candidates) {
|
||||
if (!(await isReopenable(number))) {
|
||||
core.info(`#${number} is not a closed pull request linking an accepted issue. Skipped.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: number, per_page: 100,
|
||||
});
|
||||
if (!comments.some((comment) => comment.body?.startsWith(marker))) {
|
||||
core.info(`#${number} was not closed by this gate. Left alone.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await github.rest.pulls.update({
|
||||
owner, repo, pull_number: number, state: 'open',
|
||||
});
|
||||
} catch (error) {
|
||||
core.warning(`Could not reopen #${number}: ${error.message}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: number,
|
||||
body: 'An `accepted` issue is linked now, so this is open again and ready for review.',
|
||||
});
|
||||
core.info(`Reopened #${number}`);
|
||||
}
|
||||
@@ -45,7 +45,9 @@ jobs:
|
||||
openclaw-v*) workflow="openclaw-cd.yml" ;;
|
||||
opencode-v*) workflow="opencode-plugin-cd.yml" ;;
|
||||
pi-agent-v*) workflow="pi-agent-plugin-cd.yml" ;;
|
||||
deepseek-plugin-v*) workflow="deepseek-plugin-cd.yml" ;;
|
||||
n8n-nodes-mem0-v*) workflow="n8n-nodes-mem0-cd.yml" ;;
|
||||
mem0-strands-v*) workflow="mem0-strands-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."
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
set -euo pipefail
|
||||
|
||||
base_version=$(git show "$BASE_SHA:mem0-ts/package.json" 2>/dev/null | jq -r .version || echo "")
|
||||
head_version=$(jq -r .version mem0-ts/package.json)
|
||||
head_version=$(git show "$HEAD_SHA:mem0-ts/package.json" | jq -r .version)
|
||||
|
||||
echo "Base version: ${base_version:-<unknown>}"
|
||||
echo "Head version: $head_version"
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Vouch - Check PR
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
concurrency:
|
||||
group: vouch-check-pr-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: >-
|
||||
github.event.pull_request.user.type != 'Bot' &&
|
||||
github.event.pull_request.head.repo.full_name != github.repository &&
|
||||
!contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: mitchellh/vouch/action/check-pr@d66fa29a64600490892131ad87597c30c91fcac4 # v1.5.0
|
||||
id: vouch
|
||||
with:
|
||||
pr-number: ${{ github.event.pull_request.number }}
|
||||
require-vouch: false
|
||||
auto-close: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- if: steps.vouch.outputs.status == 'allowed'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const pr = context.payload.pull_request;
|
||||
const marker = '<!-- vouch-check -->';
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner, repo, issue_number: pr.number, per_page: 100,
|
||||
});
|
||||
if (comments.some((comment) => comment.body?.startsWith(marker))) {
|
||||
core.info('Vouch comment already posted, skipped.');
|
||||
return;
|
||||
}
|
||||
|
||||
const body = [
|
||||
marker,
|
||||
`Hi @${context.payload.pull_request.user.login}, thanks for opening this pull request.`,
|
||||
'',
|
||||
"This is just a soft check: you are not yet in this repo's vouched contributor list (`.github/VOUCHED.td`). Nothing is blocked and there is nothing you need to do.",
|
||||
'',
|
||||
`A maintainer can vouch for you by commenting \`!vouch @${context.payload.pull_request.user.login}\` on any issue.`,
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner, repo, issue_number: pr.number, body,
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Vouch - Manage by Issue
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
concurrency:
|
||||
group: vouch-manage
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
manage:
|
||||
if: contains(github.event.comment.body, '!vouch') || contains(github.event.comment.body, '!denounce') || contains(github.event.comment.body, '!unvouch')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v3
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.VOUCH_APP_ID }}
|
||||
private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- uses: mitchellh/vouch/action/manage-by-issue@d66fa29a64600490892131ad87597c30c91fcac4 # v1.5.0
|
||||
with:
|
||||
repo: ${{ github.repository }}
|
||||
issue-id: ${{ github.event.issue.number }}
|
||||
comment-id: ${{ github.event.comment.id }}
|
||||
vouch-keyword: "!vouch"
|
||||
denounce-keyword: "!denounce"
|
||||
unvouch-keyword: "!unvouch"
|
||||
pull-request: "true"
|
||||
merge-immediately: "false"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
@@ -14,6 +14,10 @@ server/.env
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
!integrations/agent-plugin-core/build/
|
||||
!integrations/agent-plugin-core/build/*.py
|
||||
!integrations/agent-plugin-core/build/schemas/
|
||||
!integrations/agent-plugin-core/build/schemas/*.json
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
@@ -191,3 +195,7 @@ qdrant_storage/
|
||||
testing.ipynb
|
||||
.weave/
|
||||
|
||||
|
||||
# TypeScript incremental build info and local, uncommitted e2e scripts (used by the integrations, e.g. integrations/deepseek-plugin)
|
||||
*.tsbuildinfo
|
||||
*.local.mjs
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "mem0-plugins",
|
||||
"version": "1",
|
||||
"plugins": [
|
||||
{
|
||||
"id": "mem0",
|
||||
"displayName": "Mem0",
|
||||
"version": "0.3.3",
|
||||
"description": "Cross-session memory and token savings for coding agents.",
|
||||
"homepage": "https://mem0.ai",
|
||||
"keywords": ["memory", "personalization", "mcp", "semantic-search"],
|
||||
"source": "https://github.com/mem0ai/mem0/tree/main/integrations/kimi-plugin"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,593 +1,175 @@
|
||||
# AGENTS.md
|
||||
|
||||
This file provides context for AI coding assistants (Claude Code, Cursor, GitHub Copilot, Codex, etc.) working with the Mem0 repository.
|
||||
Context for AI coding assistants (Claude Code, Cursor, Copilot, Codex) working in the Mem0 repository.
|
||||
|
||||
## Project Overview
|
||||
**Mem0** ("mem-zero") is a memory layer for AI agents: persistent, personalized memory through a hosted platform API and self-hosted open-source SDKs. Apache-2.0.
|
||||
[Repository](https://github.com/mem0ai/mem0) · [Documentation](https://docs.mem0.ai)
|
||||
|
||||
**Mem0** ("mem-zero") is an intelligent memory layer for AI agents and assistants. It provides persistent, personalized memory via both a hosted platform API and self-hosted open-source SDKs.
|
||||
This is a polyglot monorepo and **every package sets its own rules**. Read the `AGENTS.md` nearest the files you are editing before running any command. The linters, formatters, test runners, and line lengths genuinely differ per package, and using the wrong one fails CI or produces a diff full of noise.
|
||||
|
||||
- **Repository**: https://github.com/mem0ai/mem0
|
||||
- **Documentation**: https://docs.mem0.ai
|
||||
- **License**: Apache-2.0
|
||||
## Do NOT
|
||||
|
||||
## Repository Structure
|
||||
- Open a pull request without a signed CLA. It will not be reviewed. See [The CLA is not optional](#the-cla-is-not-optional).
|
||||
- Open a pull request that does not link an issue carrying the `accepted` label. A bot closes it within a minute. See [Two gates decide whether your pull request stays open](#two-gates-decide-whether-your-pull-request-stays-open).
|
||||
- Modify anything in `.github/workflows/` without explicit maintainer approval. Publishing credentials are pinned to workflow filenames.
|
||||
- Commit `.env` files, API keys, or credentials.
|
||||
- Skip pre-commit hooks.
|
||||
- Use npm or yarn in TypeScript packages. This repo is pnpm-only (Bun in `integrations/opencode-plugin/`).
|
||||
- Use `require()` in TypeScript. ES module `import` syntax only.
|
||||
- Mix up linter configs. Root Python is ruff at line length **120**, `cli/python/` is ruff at **100**, `cli/node/` is Biome, `mem0-ts/` is Prettier, `integrations/vercel-ai-sdk/` is ESLint.
|
||||
- Add Python dependencies to the core `dependencies` list in `pyproject.toml`. Use an optional group.
|
||||
- Change a public API without updating `docs/` in the same pull request.
|
||||
- Introduce a new framework or abstraction without discussion. Follow the patterns already in the file you are editing.
|
||||
|
||||
This is a **polyglot monorepo** containing Python and TypeScript packages, CLIs, servers, plugins, and documentation.
|
||||
## Where to look
|
||||
|
||||
### Key Directories
|
||||
| Editing | Read | Toolchain |
|
||||
|---------|------|-----------|
|
||||
| `mem0/` | [`mem0/AGENTS.md`](mem0/AGENTS.md) | hatch, ruff 120, pytest |
|
||||
| `tests/` | [`tests/AGENTS.md`](tests/AGENTS.md) | pytest |
|
||||
| `mem0-ts/` | [`mem0-ts/AGENTS.md`](mem0-ts/AGENTS.md) | pnpm, tsup, Prettier, jest |
|
||||
| `cli/python/` | [`cli/python/AGENTS.md`](cli/python/AGENTS.md) | ruff **100**, pytest |
|
||||
| `cli/node/` | [`cli/node/AGENTS.md`](cli/node/AGENTS.md) | pnpm, tsup, Biome, vitest |
|
||||
| `integrations/` | [`integrations/AGENTS.md`](integrations/AGENTS.md) | varies per integration |
|
||||
| `server/` | [`server/AGENTS.md`](server/AGENTS.md) | Docker Compose, FastAPI |
|
||||
| `docs/` | [`docs/AGENTS.md`](docs/AGENTS.md) | Mintlify |
|
||||
| `skills/` | [`skills/AGENTS.md`](skills/AGENTS.md) | markdown, size-budgeted |
|
||||
| `.github/` | [`.github/AGENTS.md`](.github/AGENTS.md) | GitHub Actions |
|
||||
|
||||
| Directory | Description |
|
||||
|-----------|-------------|
|
||||
| `mem0/` | Core Python SDK (`mem0ai` on PyPI) — memory, LLMs, embeddings, vector stores, graphs, rerankers |
|
||||
| `mem0-ts/` | TypeScript SDK (`mem0ai` on npm) — client + OSS memory |
|
||||
| `cli/python/` | Python CLI (`mem0-cli` on PyPI) — Typer-based, entry point `mem0` |
|
||||
| `cli/node/` | Node CLI (`@mem0/cli` on npm) — Commander-based, entry point `mem0` |
|
||||
| `integrations/` | **Agent & editor integrations**, one directory per integration (see "Adding a New Integration") |
|
||||
| `integrations/mem0-plugin/` | AI editor plugins (Claude Code, Cursor, Codex) — MCP server connection, lifecycle hooks, skills. Contains nested `.opencode-plugin/` (`@mem0/opencode-plugin`) |
|
||||
| `integrations/openclaw/` | `@mem0/openclaw-mem0` — OpenClaw plugin for Claude Code / AI editors |
|
||||
| `integrations/pi-agent-plugin/` | `@mem0/pi-agent-plugin` — Pi Agent plugin |
|
||||
| `integrations/vercel-ai-sdk/` | `@mem0/vercel-ai-provider` — Vercel AI SDK memory provider |
|
||||
| `integrations/n8n-nodes-mem0/` | `@mem0/n8n-nodes-mem0` — n8n community node; add / search / get / update / delete memories |
|
||||
| `integrations/zapier-mem0/` | `@mem0/zapier` — Zapier Platform CLI app (deploys to Zapier, not npm); add / search / get / delete memories |
|
||||
| `server/` | FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + PostgreSQL/pgvector + Neo4j) |
|
||||
| `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/` |
|
||||
## Repository map
|
||||
|
||||
| Directory | What it is |
|
||||
|-----------|------------|
|
||||
| `mem0/` | Core Python SDK (`mem0ai` on PyPI): memory, LLMs, embeddings, vector stores, graphs, rerankers |
|
||||
| `mem0-ts/` | TypeScript SDK (`mem0ai` on npm): hosted client + OSS memory |
|
||||
| `cli/python/` | Python CLI (`mem0-cli` on PyPI), Typer-based, entry point `mem0` |
|
||||
| `cli/node/` | Node CLI (`@mem0/cli` on npm), Commander-based, entry point `mem0` |
|
||||
| `integrations/` | Agent and editor integrations, one self-contained directory each |
|
||||
| `server/` | FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + pgvector + Neo4j) |
|
||||
| `skills/` | Claude Code skill definitions, published by raw URL |
|
||||
| `docs/` | Documentation site (Mintlify) |
|
||||
| `tests/` | Python SDK tests (pytest) |
|
||||
| `evaluation/` | Submodule → [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) — benchmarking (LOCOMO, LongMemEval, BEAM) lives in that repo |
|
||||
| `examples/` | Sample projects & runnable demos — apps, Chrome extension, multi-agent patterns, and Jupyter notebooks (`notebooks/`) |
|
||||
| `examples/` | Sample apps, Chrome extension, multi-agent patterns, notebooks |
|
||||
| `scripts/` | Repo-wide utilities, e.g. `check-llms-txt-coverage.py` |
|
||||
| `evaluation/` | Submodule pinned to [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) |
|
||||
| `pr-reviews/` | Pull request review materials |
|
||||
| `scripts/` | Repo-wide utility scripts (e.g., `check-llms-txt-coverage.py` for docs/llms.txt sync) |
|
||||
|
||||
### Core Package Dependencies
|
||||
|
||||
```
|
||||
mem0 (Python SDK) mem0-ts (TypeScript SDK)
|
||||
├── mem0/memory/ ├── src/client/ (MemoryClient — hosted)
|
||||
├── mem0/llms/ └── src/oss/ (Memory — self-hosted)
|
||||
├── mem0/memory/ ├── src/client/ MemoryClient (hosted)
|
||||
├── mem0/llms/ └── src/oss/ Memory (self-hosted)
|
||||
├── mem0/embeddings/ ├── src/llms/
|
||||
├── mem0/vector_stores/ ├── src/embeddings/
|
||||
├── mem0/graphs/ ├── src/vector_stores/
|
||||
└── mem0/reranker/ └── src/graphs/
|
||||
|
||||
cli/python/ ──▶ mem0ai (optional, for OSS mode)
|
||||
cli/node/ ──▶ mem0ai (npm, for API calls)
|
||||
integrations/vercel-ai-sdk/ ──▶ ai, @ai-sdk/* providers
|
||||
integrations/openclaw/ ──▶ mem0ai (npm)
|
||||
cli/python/ ──▶ mem0ai (optional, OSS mode)
|
||||
cli/node/ ──▶ mem0ai (npm)
|
||||
integrations/vercel-ai-sdk/ ──▶ ai, @ai-sdk/*
|
||||
integrations/openclaw/ ──▶ mem0ai (npm)
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Requirements
|
||||
|
||||
- **Python**: 3.9+ (3.10+ for CLI)
|
||||
- **Node.js**: v18+ (v20 or v22 recommended)
|
||||
- **pnpm**: v10+ (`npm install -g pnpm@10`) — used for all TypeScript packages
|
||||
- **Hatch**: Python build/environment tool (`pip install hatch`)
|
||||
- **Docker**: Required for `server/` development
|
||||
|
||||
### Initial Setup
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# Python SDK
|
||||
hatch shell dev_py_3_11 # creates environment with all deps
|
||||
pre-commit install # install git hooks
|
||||
hatch shell dev_py_3_11 # Python: creates the env with all deps
|
||||
pre-commit install # ruff + isort on commit
|
||||
|
||||
# TypeScript packages
|
||||
cd mem0-ts && pnpm install # TS SDK
|
||||
cd cli/node && pnpm install # Node CLI
|
||||
cd integrations/vercel-ai-sdk && pnpm install # Vercel AI provider
|
||||
cd integrations/openclaw && pnpm install # OpenClaw plugin
|
||||
cd <ts-package> && pnpm install
|
||||
```
|
||||
|
||||
## Build, Lint, and Test Commands
|
||||
Requirements: Python 3.9+ (3.10+ for the CLI), Node 18+ (20 or 22 preferred), pnpm 10+, hatch, Docker for `server/`.
|
||||
|
||||
### Python SDK (`mem0/`)
|
||||
## Conventions everywhere
|
||||
|
||||
- **Naming:** `snake_case.py`, `test_<module>.py`, `snake_case.ts`, `<module>.test.ts`, `kebab-case` for config and manifest files.
|
||||
- **Python:** Pydantic v2 for models and config. Providers inherit a `base.py` abstract class; config lives in `configs.py`.
|
||||
- **TypeScript:** strict mode, tsup builds, ES module imports.
|
||||
- **Commits:** [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`).
|
||||
- **Versions:** bump in `pyproject.toml` or `package.json`. Releases are cut by tag prefix; see [`.github/AGENTS.md`](.github/AGENTS.md).
|
||||
|
||||
## Benchmarking
|
||||
|
||||
Benchmarks (LOCOMO, LongMemEval, BEAM) live in [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks). The in-repo `evaluation/` path is a submodule pinned to that repo's `main`:
|
||||
|
||||
```bash
|
||||
# Environment setup (uses Hatch)
|
||||
hatch shell dev_py_3_11 # or dev_py_3_9, dev_py_3_10, dev_py_3_12
|
||||
|
||||
# Linting and formatting
|
||||
make lint # ruff check
|
||||
make format # ruff format
|
||||
make sort # isort mem0/
|
||||
|
||||
# Tests
|
||||
make test # pytest tests/
|
||||
make test-py-3.9 # test specific Python version (3.9–3.12)
|
||||
|
||||
# Build and publish
|
||||
make build # hatch build
|
||||
make publish # hatch publish
|
||||
git submodule update --init evaluation
|
||||
```
|
||||
|
||||
- **Python:** 3.9, 3.10, 3.11, 3.12
|
||||
- **Linter/formatter:** Ruff (line length **120**)
|
||||
- **Import sorting:** isort (`profile = "black"`)
|
||||
- **Test framework:** pytest (with pytest-mock, pytest-asyncio)
|
||||
- **Pre-commit hooks:** ruff + isort — run `pre-commit install` before committing
|
||||
## What to ship with a change
|
||||
|
||||
### TypeScript SDK (`mem0-ts/`)
|
||||
Guidelines, not rules. Trivial fixes need less; anything user-facing needs more.
|
||||
|
||||
```bash
|
||||
cd mem0-ts
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run test # jest (all tests)
|
||||
pnpm run test:unit # jest --coverage (unit tests only)
|
||||
pnpm run test:integration # jest (integration tests, needs MEM0_API_KEY)
|
||||
pnpm run test:ci # jest --coverage --ci (CI mode)
|
||||
pnpm run test:watch # jest watch mode
|
||||
```
|
||||
| Change | Expect |
|
||||
|--------|--------|
|
||||
| **Bug fix** | A regression test that fails without the fix, written first. The fix. The relevant suite passing. The package's linter run. |
|
||||
| **New feature** | Implementation following existing patterns, test coverage, `docs/` updates for public APIs, an example if the behavior is user-facing, and an `llms.txt` entry for any new `.mdx` page. |
|
||||
| **New provider** | See [Adding a provider](mem0/AGENTS.md#adding-a-provider). |
|
||||
| **New integration** | See [Adding an integration](integrations/AGENTS.md#adding-an-integration). |
|
||||
| **Refactor** | Tests for changed behavior, existing tests still green. No docs needed for internal-only changes. |
|
||||
|
||||
- **Node:** 20, 22 (CI-tested)
|
||||
- **Build:** tsup (CJS + ESM)
|
||||
- **Test:** jest
|
||||
- **Formatter:** prettier
|
||||
Fix bugs at the root, not at the symptom. If a guard belongs in a shared function, put it there rather than in each caller.
|
||||
|
||||
### Python CLI (`cli/python/`)
|
||||
## Contributing
|
||||
|
||||
```bash
|
||||
cd cli/python
|
||||
pip install -e ".[dev]" # dev install with ruff + pytest
|
||||
ruff check . # lint
|
||||
ruff format . # format
|
||||
pytest # test
|
||||
hatch build # build
|
||||
```
|
||||
Full guide: [`CONTRIBUTING.md`](CONTRIBUTING.md). Conduct: [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).
|
||||
|
||||
- **Python:** 3.10+ (not 3.9)
|
||||
- **Linter/formatter:** Ruff (line length **100** — different from root SDK)
|
||||
- **Ruff rules:** E, F, I, W, UP, B, SIM, RUF (ignores E501, B008 for Typer patterns, SIM108)
|
||||
- **Framework:** Typer + Rich + httpx
|
||||
- **Entry point:** `mem0 = "mem0_cli.app:main"`
|
||||
- **Source layout:** `src/mem0_cli/`
|
||||
- **Optional dependency:** `mem0ai` (for OSS mode, via `[oss]` extra)
|
||||
1. Open an issue **first** and wait for a maintainer to apply the `accepted` label. Every PR must link it with `Closes #<number>`. PRs without an accepted linked issue are closed automatically by the [PR Gate](.github/workflows/pr-gate.yml), with a reopen path. Documentation-only changes are exempt.
|
||||
2. Fork, then branch from `main` (`feature/...`, `fix/...`).
|
||||
3. Make the change: code, tests, docs, examples.
|
||||
4. Run lint and tests for **every** package you touched.
|
||||
5. Commit with Conventional Commits.
|
||||
6. Open the PR against `main` and fill in [the template](.github/PULL_REQUEST_TEMPLATE.md). Do not paraphrase it; GitHub prefills it.
|
||||
7. **Sign the CLA.**
|
||||
|
||||
### Node CLI (`cli/node/`)
|
||||
### Two gates decide whether your pull request stays open
|
||||
|
||||
```bash
|
||||
cd cli/node
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run lint # biome check src/
|
||||
pnpm run lint:fix # biome check --write src/
|
||||
pnpm run typecheck # tsc --noEmit
|
||||
pnpm run test # vitest run
|
||||
pnpm run test:watch # vitest (watch mode)
|
||||
pnpm run dev # tsx src/index.ts (development)
|
||||
```
|
||||
Two workflows run on every pull request from a fork. They judge different things and neither covers for the other, so a pull request has to get past both.
|
||||
|
||||
- **Node:** 18+ required
|
||||
- **Build:** tsup (ESM)
|
||||
- **Linter:** Biome (not ESLint, not Ruff)
|
||||
- **Test:** vitest (not jest)
|
||||
- **Framework:** Commander + Chalk + ora + cli-table3
|
||||
**The [PR Gate](.github/workflows/pr-gate.yml) judges the change.** It closes any pull request that does not link an issue carrying the `accepted` label. Closed is a queue decision, not a verdict: when a maintainer applies the label the pull request reopens by itself. Drafts, documentation-only changes, and branches pushed to this repository rather than a fork are all exempt.
|
||||
|
||||
### Vercel AI SDK Provider (`integrations/vercel-ai-sdk/`)
|
||||
**The [vouch check](.github/workflows/vouch-check-pr.yml) judges the account.** It reads [`.github/VOUCHED.td`](.github/VOUCHED.td), which has three possible answers about any given person:
|
||||
|
||||
```bash
|
||||
cd integrations/vercel-ai-sdk
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run lint # eslint
|
||||
pnpm run type-check # tsc --noEmit
|
||||
pnpm run prettier-check # prettier --check
|
||||
pnpm run test # jest
|
||||
pnpm run test:edge # vitest (edge runtime)
|
||||
pnpm run test:node # vitest (node runtime)
|
||||
```
|
||||
| The list says | Meaning | Effect on the pull request |
|
||||
|---|---|---|
|
||||
| `-handle` | a maintainer ran `!denounce` after the code of conduct process | closed, even with an accepted issue |
|
||||
| nothing at all | everybody who has not contributed here before | **none.** One comment saying nothing is blocked. |
|
||||
| `handle` | a maintainer ran `!vouch` | none, and the comment stops appearing |
|
||||
|
||||
- **Build:** tsup (CJS + ESM)
|
||||
- **Lint:** ESLint + Prettier
|
||||
- **Test:** jest + vitest (edge/node configs)
|
||||
Being vouched grants nothing. It is a "we have seen this person before" flag that mutes the newcomer comment, not permission to skip the accepted-issue rule. Being absent from the list costs nothing.
|
||||
|
||||
### OpenClaw Plugin (`integrations/openclaw/`)
|
||||
If you are an agent opening a pull request on someone's behalf, the practical consequence is one rule: **get the linked issue labelled `accepted` before you open the pull request, or expect the pull request to be closed and to reopen later.** Do not work around either gate, do not reopen a gated pull request by hand, and do not re-file the same change under a new pull request when one is closed.
|
||||
|
||||
```bash
|
||||
cd integrations/openclaw
|
||||
pnpm install
|
||||
pnpm run build # tsup
|
||||
pnpm run test # vitest run
|
||||
```
|
||||
### The CLA is not optional
|
||||
|
||||
- **Build:** tsup (ESM)
|
||||
- **Test:** vitest (with Codecov in CI)
|
||||
- **Plugin manifest:** `openclaw.plugin.json`
|
||||
**A pull request from a contributor who has not signed the Contributor License Agreement is not accepted, not reviewed, and not merged.** This is not a formality applied at merge time. An unsigned pull request does not enter the review queue at all: maintainers do not read the diff, do not leave feedback, and do not discuss the approach. It sits until the CLA is signed, and it is closed if it goes stale.
|
||||
|
||||
### Server (`server/`)
|
||||
The `CLAassistant` bot comments on your first pull request with a link. Signing takes under a minute, is done once per GitHub account, and covers every contribution you make afterwards. Until it is signed the `license/cla` check stays red.
|
||||
|
||||
```bash
|
||||
# Docker production build
|
||||
cd server
|
||||
make build # docker build -t mem0-api-server .
|
||||
make run_local # docker run -p 8000:8000 with .env
|
||||
If you are an agent opening a pull request on someone's behalf, tell them they must sign it themselves. Nobody else can sign for them, and the pull request goes nowhere until they do.
|
||||
|
||||
# Docker Compose development (FastAPI + PostgreSQL/pgvector + Neo4j)
|
||||
cd server
|
||||
docker-compose up # starts all 3 services
|
||||
# mem0 API: localhost:8888
|
||||
# PostgreSQL: localhost:8432
|
||||
# Neo4j HTTP: localhost:8474, Bolt: localhost:8687
|
||||
```
|
||||
### What gets a pull request closed
|
||||
|
||||
- **Framework:** FastAPI with uvicorn (auto-reload in dev)
|
||||
- **Services:** PostgreSQL with pgvector, Neo4j 5.x with APOC plugin
|
||||
- **Hot reload:** Dev Dockerfile mounts `server/` and `mem0/` for live changes
|
||||
Beyond the CLA and the accepted-issue gate, the [Contribution Conduct](CODE_OF_CONDUCT.md#contribution-conduct) section of the code of conduct is the enforceable form of this repo's anti-slop policy:
|
||||
|
||||
### Documentation (`docs/`)
|
||||
- **Disclose AI use.** The PR template asks how the *code* was written; drafting the description with a model is fine. The disclosure is never held against you, it tells a reviewer where to look. Silence followed by a review comment you cannot answer is what costs everyone the afternoon.
|
||||
- **Do not submit work you have not run.** A bug report means you reproduced it. A PR means you ran the tests.
|
||||
- **Do not fabricate evidence.** Invented tracebacks, unmeasured benchmarks, tests that assert the implementation back at itself, descriptions that describe a different change than the diff makes.
|
||||
- **Match your volume to your engagement.** Open changes at the rate you can discuss them.
|
||||
- **Do not press for merges.** One polite follow-up after a reasonable wait is fine.
|
||||
- **You must be able to explain every line of your diff** and how it interacts with the rest of the codebase, without asking an AI tool. This is the one rule that does not bend.
|
||||
|
||||
```bash
|
||||
make docs # or: cd docs && mintlify dev
|
||||
```
|
||||
### Reference
|
||||
|
||||
- **Framework:** Mintlify
|
||||
- **API spec:** `docs/openapi.json`
|
||||
- **Structure:** `api-reference/`, `open-source/`, `platform/`, `integrations/`, `cookbooks/`, `core-concepts/`
|
||||
|
||||
### Evaluation / Benchmarking
|
||||
|
||||
Benchmarking lives in the external [`mem0ai/memory-benchmarks`](https://github.com/mem0ai/memory-benchmarks) repo (LOCOMO + LongMemEval + BEAM). The in-repo `evaluation/` path is a **git submodule** pinned to that repo's `main` — populate it with `git submodule update --init evaluation` (or clone mem0 with `--recurse-submodules`), or clone the benchmarks repo standalone:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mem0ai/memory-benchmarks.git
|
||||
cd memory-benchmarks
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run a benchmark (Mem0 Cloud; use docker compose for OSS)
|
||||
python -m benchmarks.locomo.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY
|
||||
python -m benchmarks.longmemeval.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --all-questions
|
||||
python -m benchmarks.beam.run --project-name my-test --backend cloud --mem0-api-key $MEM0_API_KEY --chat-sizes 100K --conversations 0-9
|
||||
```
|
||||
|
||||
## Core APIs
|
||||
|
||||
### Python
|
||||
|
||||
| Function / Class | Purpose | Import |
|
||||
|-----------------|---------|--------|
|
||||
| `Memory` | Self-hosted memory (sync) | `from mem0 import Memory` |
|
||||
| `AsyncMemory` | Self-hosted memory (async) | `from mem0 import AsyncMemory` |
|
||||
| `MemoryClient` | Hosted platform client (sync) | `from mem0 import MemoryClient` |
|
||||
| `AsyncMemoryClient` | Hosted platform client (async) | `from mem0 import AsyncMemoryClient` |
|
||||
|
||||
**Key `Memory` / `MemoryClient` methods:**
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `add(messages, *, user_id, agent_id, run_id, metadata)` | Store a new memory |
|
||||
| `search(query, *, user_id, agent_id, run_id, limit, filters)` | Search memories |
|
||||
| `get(memory_id)` | Retrieve a single memory by ID |
|
||||
| `get_all(*, user_id, agent_id, run_id, limit)` | List all memories |
|
||||
| `update(memory_id, data)` | Update a memory |
|
||||
| `delete(memory_id)` | Delete a memory |
|
||||
| `delete_all(*, user_id, agent_id, run_id)` | Delete all memories |
|
||||
| `history(memory_id)` | Get change history for a memory |
|
||||
|
||||
### TypeScript
|
||||
|
||||
| Export | Purpose | Import |
|
||||
|--------|---------|--------|
|
||||
| `MemoryClient` | Hosted platform client | `import { MemoryClient } from 'mem0ai'` |
|
||||
| `Memory` | Self-hosted OSS memory | `import { Memory } from 'mem0ai/oss'` |
|
||||
|
||||
## Import Patterns
|
||||
|
||||
### Python
|
||||
|
||||
| What | Import |
|
||||
|------|--------|
|
||||
| Core memory classes | `from mem0 import Memory, AsyncMemory` |
|
||||
| Platform client | `from mem0 import MemoryClient, AsyncMemoryClient` |
|
||||
| Configuration | `from mem0.configs.base import MemoryConfig` |
|
||||
| LLM providers | `from mem0.llms.<provider> import <ProviderLLM>` |
|
||||
| Embedding providers | `from mem0.embeddings.<provider> import <ProviderEmbedding>` |
|
||||
| Vector store providers | `from mem0.vector_stores.<provider> import <ProviderVectorStore>` |
|
||||
|
||||
### TypeScript
|
||||
|
||||
| What | Import |
|
||||
|------|--------|
|
||||
| Hosted client | `import { MemoryClient } from 'mem0ai'` |
|
||||
| OSS memory | `import { Memory } from 'mem0ai/oss'` |
|
||||
| Specific providers (OSS) | `import { OpenAIEmbedding } from 'mem0ai/oss'` |
|
||||
|
||||
## Coding Standards
|
||||
|
||||
### File Naming Conventions
|
||||
|
||||
- **Python source files:** `snake_case.py` (e.g., `azure_openai.py`, `cohere_reranker.py`)
|
||||
- **Python test files:** `test_<module>.py` (e.g., `test_memory.py`, `test_main.py`)
|
||||
- **TypeScript source files:** `snake_case.ts` (e.g., `azure_ai_search.ts`)
|
||||
- **TypeScript test files:** `<module>.test.ts` (e.g., `memory.test.ts`)
|
||||
- **Config/manifest files:** `kebab-case` (e.g., `openclaw.plugin.json`, `jest.config.js`)
|
||||
|
||||
### Python Conventions
|
||||
|
||||
- **Provider pattern:** All providers (LLMs, embeddings, vector stores, graphs, rerankers) inherit from a `base.py` abstract class in their directory. Config classes live in `configs.py`.
|
||||
- **Pydantic v2** for all data models and configuration.
|
||||
- **Ruff** is the single linting and formatting tool — no black, no flake8.
|
||||
- Root SDK: line length **120**
|
||||
- Python CLI: line length **100** with extended rule set (UP, B, SIM, RUF)
|
||||
- **isort** with `profile = "black"` for import sorting.
|
||||
|
||||
### TypeScript Conventions
|
||||
|
||||
- **Build:** tsup across all packages.
|
||||
- **Package manager:** pnpm everywhere (no npm, no yarn).
|
||||
- **TypeScript strict mode** across all packages.
|
||||
- **Linting varies by package:**
|
||||
|
||||
| Package | Linter | Formatter | Test Framework |
|
||||
|---------|--------|-----------|---------------|
|
||||
| `mem0-ts/` | — | Prettier | jest |
|
||||
| `cli/node/` | Biome | Biome | vitest |
|
||||
| `integrations/vercel-ai-sdk/` | ESLint | Prettier | jest + vitest |
|
||||
| `integrations/openclaw/` | — | — | vitest |
|
||||
|
||||
### Type Checking
|
||||
|
||||
Always run type checking after modifying TypeScript code:
|
||||
|
||||
```bash
|
||||
cd <package> && pnpm run typecheck # or: tsc --noEmit
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Provider Pattern
|
||||
|
||||
The SDK uses a consistent plugin architecture across 5 categories. Each category has a `base.py` abstract class and concrete provider implementations:
|
||||
|
||||
| Category | Count | Examples |
|
||||
|----------|-------|---------|
|
||||
| **LLMs** | 24 | OpenAI, Anthropic, AWS Bedrock, Azure OpenAI, Gemini, Groq, Ollama, Together, DeepSeek, vLLM, LiteLLM, LM Studio, xAI |
|
||||
| **Vector Stores** | 30 | Qdrant, Pinecone, Chroma, Weaviate, Milvus, MongoDB, Redis, Elasticsearch, pgvector, Supabase, Faiss, S3 Vectors |
|
||||
| **Embeddings** | 15 | OpenAI, Azure OpenAI, Gemini, HuggingFace, FastEmbed, Together, AWS Bedrock, Ollama, Vertex AI |
|
||||
| **Graph Stores** | 4 | Neo4j, Memgraph, Kuzu, Apache AGE |
|
||||
| **Rerankers** | 5 | Cohere, HuggingFace, LLM-based, Sentence Transformer, Zero Entropy |
|
||||
|
||||
### Two Usage Modes
|
||||
|
||||
Self-hosted `Memory` / `AsyncMemory` classes and hosted-platform `MemoryClient` — both in Python and TypeScript.
|
||||
|
||||
### Graph Memory
|
||||
|
||||
Optional layer on top of vector memory for relationship-aware retrieval. Configured via the `graph` section of `MemoryConfig`.
|
||||
|
||||
### MCP Integration
|
||||
|
||||
Model Context Protocol support in multiple places:
|
||||
|
||||
- **Remote:** MCP server at `mcp.mem0.ai`
|
||||
- **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
|
||||
|
||||
- `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:
|
||||
- **Reference skills** (always-on SDK knowledge): `mem0` (Python + TS SDKs, framework integrations), `mem0-cli` (terminal workflows), `mem0-vercel-ai-sdk` (Vercel AI provider).
|
||||
- **Pipeline skills** (run on demand): `mem0-integrate` wires Mem0 into an existing repo via a TDD pipeline; `mem0-test-integration` verifies what the integrator produced on the same branch (the two are loosely coupled via `.mem0-integration/` artifacts); `mem0-oss-to-platform` migrates an existing project from Mem0 OSS to the hosted Platform SDK (plan, then execute on approval).
|
||||
|
||||
### Adding a New Provider
|
||||
|
||||
To add a new LLM, embedding, vector store, or reranker provider:
|
||||
|
||||
1. Create `mem0/<category>/<provider_name>.py`
|
||||
2. Inherit from the abstract base class in `mem0/<category>/base.py`
|
||||
3. Add configuration to `mem0/<category>/configs.py` (if the category uses one)
|
||||
4. Register the provider in `mem0/<category>/__init__.py`
|
||||
5. Add tests in `tests/<category>/<provider_name>/`
|
||||
6. Add any new dependencies to the appropriate optional group in `pyproject.toml` (never to core `dependencies`)
|
||||
7. Follow the exact pattern of existing providers in the same category — match method signatures, error handling, and config structure
|
||||
|
||||
### Adding a New Integration
|
||||
|
||||
Agent/editor integrations live under `integrations/`. Each is a self-contained directory (its own `package.json`/lockfile, build, and tests). To add one:
|
||||
|
||||
1. Create `integrations/<name>/` and build the integration there.
|
||||
2. If it publishes to a registry, set `repository.directory: "integrations/<name>"` in its `package.json` so npm provenance links to the correct subdirectory.
|
||||
3. Add CI/CD under `.github/workflows/` (`<name>-checks.yml`, `<name>-cd.yml`). Use `integrations/<name>` in `paths:` triggers, `working-directory`, and `cache-dependency-path`. Register the release tag prefix in the `case` block in `release.yml` (keep the bare `v*` arm last). Keep workflow **filenames** stable — npm OIDC trusted publishing is pinned to repo + workflow filename.
|
||||
4. If it is a Claude Code / editor marketplace plugin, register its path in the five `marketplace.json` files (root + `.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/`, `.agents/plugins/`).
|
||||
5. Document it under `docs/integrations/` and add the page to `docs/docs.json` and `docs/llms.txt`.
|
||||
6. Add rows to the "Key Directories" table and the CI/CD tables in this file.
|
||||
|
||||
## CI/CD
|
||||
|
||||
### CI Workflows (automated testing)
|
||||
|
||||
PR testing is orchestrated by a single entry point: **`ci-gate.yml` (CI Gate)** runs on every PR, detects which packages changed, and invokes only the relevant package workflows below as reusable workflows (`workflow_call`). Its final **`CI Gate`** job aggregates the results (skipped pipelines pass; failed or cancelled ones fail) and is the **only status check that needs to be required** in branch protection. Package workflows keep their own push-to-main and manual triggers; their `pull_request` triggers moved into the gate's path filters.
|
||||
|
||||
| Workflow | File | Standalone Triggers | Tests |
|
||||
|----------|------|---------------------|-------|
|
||||
| CI Gate | `ci-gate.yml` | All PRs | Routes to and aggregates the workflows below |
|
||||
| Python SDK | `ci.yml` | Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
|
||||
| TypeScript SDK | `ts-sdk-ci.yml` | Push to main (on `mem0-ts/`) | Prettier + build + jest on Node 20, 22 |
|
||||
| Python CLI | `cli-python-ci.yml` | Push to main (on `cli/python/`), manual | Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
|
||||
| Node CLI | `cli-node-ci.yml` | Push to main (on `cli/node/`), manual | Biome lint + tsc + vitest + tsup build on Node 20, 22 |
|
||||
| OpenClaw | `openclaw-checks.yml` | Push to main (on `integrations/openclaw/`), manual | tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
|
||||
| Mem0 Plugin | `mem0-plugin-checks.yml` | Push to main (on `integrations/mem0-plugin/`, excluding `.opencode-plugin/`), manual | pytest + hook entry-point exec bits + JSON manifest validation on Python 3.10, 3.11, 3.12 |
|
||||
| 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 |
|
||||
| n8n Node | `n8n-nodes-mem0-checks.yml` | Push to main (on `integrations/n8n-nodes-mem0/`), manual | ESLint (n8n-nodes-base) + tsc build (dist artifact check) on Node 20 |
|
||||
| Zapier App | `zapier-mem0-checks.yml` | Push to main (on `integrations/zapier-mem0/`), manual | build (tsc) + `zapier validate` + offline unit tests on Node 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)
|
||||
|
||||
Publishing is routed through a single entry point: **`release.yml` (Release Router)** is the only workflow that listens to `release: published` events. It matches the release tag prefix and dispatches the corresponding package workflow via `workflow_dispatch`, so each release produces exactly one routed run (no skipped runs from the other pipelines).
|
||||
|
||||
| Workflow | File | Tag Prefix | Target |
|
||||
|----------|------|------------|--------|
|
||||
| Release Router | `release.yml` | (all releases) | dispatches the matching workflow below |
|
||||
| Python SDK | `cd.yml` | `v*` | PyPI (`mem0ai`) |
|
||||
| TypeScript SDK | `ts-sdk-cd.yml` | `ts-v*` | npm (`mem0ai`) |
|
||||
| Python CLI | `cli-python-cd.yml` | `cli-v*` | PyPI (`mem0-cli`) |
|
||||
| Node CLI | `cli-node-cd.yml` | `cli-node-v*` | npm (`@mem0/cli`) |
|
||||
| Vercel AI SDK | `vercel-ai-cd.yml` | `vercel-ai-v*` | npm (`@mem0/vercel-ai-provider`) |
|
||||
| OpenClaw | `openclaw-cd.yml` | `openclaw-v*` | npm (`@mem0/openclaw-mem0`) |
|
||||
| OpenCode Plugin | `opencode-plugin-cd.yml` | `opencode-v*` | npm (`@mem0/opencode-plugin`) |
|
||||
| Pi Agent Plugin | `pi-agent-plugin-cd.yml` | `pi-agent-v*` | npm (`@mem0/pi-agent-plugin`) |
|
||||
| n8n Node | `n8n-nodes-mem0-cd.yml` | `n8n-nodes-mem0-v*` | npm (`@mem0/n8n-nodes-mem0`) |
|
||||
|
||||
- Package CD workflows are `workflow_dispatch`-only (inputs: `tag`, `prerelease`); they check out and build the given tag. Registry trusted-publisher settings stay pinned to each package's own workflow filename.
|
||||
- All publishing uses **OIDC trusted publishing** — no tokens or secrets required.
|
||||
- First publish of a new npm package must be done manually; OIDC works for subsequent versions.
|
||||
- To re-publish a release (e.g. after a registry settings fix), do **not** delete/recreate the GitHub release — manually dispatch the package workflow instead: `gh workflow run <package>-cd.yml --ref refs/tags/<tag> -f tag=<tag>`.
|
||||
- The **Zapier app** (`integrations/zapier-mem0`) deploys to Zapier's own platform, not npm, so it is **not** in the release router. Deploy it manually: `gh workflow run zapier-mem0-cd.yml --ref main` (requires the `ZAPIER_DEPLOY_KEY` secret).
|
||||
- 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
|
||||
|
||||
| Workflow | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| Issue Labeler | `issue-labeler.yml` | Automatic issue labeling |
|
||||
| PR Labeler | `pr-labeler.yml` | Path-based PR labeling plus propagating labels from linked issues |
|
||||
| Stale Bot | `stale.yml` | Marks stale issues and PRs |
|
||||
| llms.txt Check | `docs-llms-txt-check.yml` | Blocks PRs touching `docs/**/*.mdx` when `docs/llms.txt` is out of sync. Fix locally with `python scripts/check-llms-txt-coverage.py --write`. |
|
||||
|
||||
## Task Completion Guidelines
|
||||
|
||||
These guidelines outline typical artifacts for different task types. Use judgment to adapt based on scope and context.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
1. **Unit tests**: Add tests that would fail without the fix (regression tests)
|
||||
2. **Implementation**: Fix the bug
|
||||
3. **Manual verification**: Run the relevant test suite to confirm the fix
|
||||
4. **Lint**: Run the appropriate linter for the package you modified
|
||||
|
||||
### New Features
|
||||
|
||||
1. **Implementation**: Build the feature following existing patterns
|
||||
2. **Unit tests**: Comprehensive test coverage for new functionality
|
||||
3. **Documentation**: Update relevant docs in `docs/` for public APIs
|
||||
4. **Examples**: Add usage examples if the feature introduces new user-facing behavior
|
||||
5. **llms.txt**: Any new `.mdx` page under `docs/` must be linked in `docs/llms.txt` with a scope tag (`[Platform]` / `[OSS]` / `[Both]`) and a `Use when ...` description. The `docs-llms-txt-check.yml` workflow runs on every PR that touches docs and **fails the check** if the index is out of sync. To fix: run `python scripts/check-llms-txt-coverage.py --write` locally to scaffold placeholders under `## Unclassified - needs triage`, then replace the `[TODO: ...]` tags, rewrite descriptions as `Use when ...`, move entries into the right section, and delete the triage heading when empty.
|
||||
|
||||
### New Provider (LLM / Embedding / Vector Store / Reranker)
|
||||
|
||||
1. **Implementation**: Follow the "Adding a New Provider" steps above
|
||||
2. **Tests**: Add unit tests matching the pattern of existing providers
|
||||
3. **Configuration**: Add to the appropriate `configs.py` and `__init__.py`
|
||||
4. **Dependencies**: Add to the correct optional group in `pyproject.toml`
|
||||
5. **Documentation**: Add an integration guide in `docs/integrations/`
|
||||
|
||||
### Refactoring / Internal Changes
|
||||
|
||||
- Unit tests for any changed behavior
|
||||
- No documentation needed for internal-only changes
|
||||
- Ensure all existing tests still pass
|
||||
|
||||
### When to Deviate
|
||||
|
||||
These are guidelines, not rigid rules. Adjust based on:
|
||||
|
||||
- **Scope**: Trivial fixes (typos, comments) may not need tests
|
||||
- **Visibility**: Internal changes may not need documentation
|
||||
- **Context**: Some changes span multiple categories — use judgment
|
||||
|
||||
When uncertain about expected artifacts, ask for clarification.
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Workflow
|
||||
|
||||
1. Fork and clone the repository.
|
||||
2. Create a feature branch from `main` (e.g., `feature/my-new-feature`).
|
||||
3. Make your changes — add tests, docs, and examples as appropriate.
|
||||
4. Run linting and tests for every package you modified (see commands above).
|
||||
5. Run `pre-commit install` on first setup — hooks run ruff + isort automatically.
|
||||
6. Commit with a clear message following [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat:`, `fix:`, `docs:`, `refactor:`).
|
||||
7. Push and open a Pull Request against `main`.
|
||||
|
||||
### Pull Request Requirements
|
||||
|
||||
Every PR must follow the repo's PR template (`.github/PULL_REQUEST_TEMPLATE.md`):
|
||||
|
||||
1. **Linked Issue** — Reference the issue with `Closes #<number>`. If no issue exists, create one first or explain why in the description.
|
||||
2. **Description** — Explain what the PR does and why it's needed.
|
||||
3. **Type of Change** — Check the appropriate box:
|
||||
- Bug fix / New feature / Breaking change / Refactor / Documentation update
|
||||
4. **Breaking Changes** — If applicable, describe what breaks and the migration path.
|
||||
5. **Test Coverage** — Check what applies:
|
||||
- Added/updated unit tests
|
||||
- Added/updated integration tests
|
||||
- Tested manually (describe how)
|
||||
- No tests needed (explain why)
|
||||
6. **Checklist** — All must be checked before merge:
|
||||
- [ ] Code follows the project's style guidelines
|
||||
- [ ] Self-review performed
|
||||
- [ ] Tests added that prove the fix/feature works
|
||||
- [ ] New and existing tests pass locally
|
||||
- [ ] Documentation updated if needed
|
||||
|
||||
### PR Description Template
|
||||
|
||||
```markdown
|
||||
## Linked Issue
|
||||
|
||||
Closes #<!-- issue number -->
|
||||
|
||||
## Description
|
||||
|
||||
<!-- What does this PR do? Why is it needed? -->
|
||||
|
||||
## Type of Change
|
||||
|
||||
- [ ] Bug fix (non-breaking change that fixes an issue)
|
||||
- [ ] New feature (non-breaking change that adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
- [ ] Refactor (no functional changes)
|
||||
- [ ] Documentation update
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
N/A
|
||||
|
||||
## Test Coverage
|
||||
|
||||
- [ ] I added/updated unit tests
|
||||
- [ ] I added/updated integration tests
|
||||
- [ ] I tested manually (describe below)
|
||||
- [ ] No tests needed (explain why)
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] My code follows the project's style guidelines
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have added tests that prove my fix/feature works
|
||||
- [ ] New and existing tests pass locally
|
||||
- [ ] I have updated documentation if needed
|
||||
```
|
||||
|
||||
### General Rules
|
||||
|
||||
- Follow existing code patterns — don't introduce new frameworks or abstractions without discussion.
|
||||
- Version bumps go in `pyproject.toml` (Python) or `package.json` (TypeScript).
|
||||
- For `server/` work, use Docker Compose for local development.
|
||||
- Do NOT use `pip` or `conda` for dependency management — use `hatch` (see `docs/contributing/development.mdx`).
|
||||
|
||||
### Contributing Guides
|
||||
|
||||
| Task | Guide |
|
||||
|------|-------|
|
||||
| Code contributions | `docs/contributing/development.mdx` |
|
||||
| Topic | File |
|
||||
|-------|------|
|
||||
| Contributor guide | [`CONTRIBUTING.md`](CONTRIBUTING.md) |
|
||||
| Code of conduct | [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) |
|
||||
| Security reports | [`SECURITY.md`](SECURITY.md) |
|
||||
| Development setup | `docs/contributing/development.mdx` |
|
||||
| Documentation contributions | `docs/contributing/documentation.mdx` |
|
||||
| PR template | `.github/PULL_REQUEST_TEMPLATE.md` |
|
||||
| Bug reports | `.github/ISSUE_TEMPLATE/bug_report.yml` |
|
||||
| Feature requests | `.github/ISSUE_TEMPLATE/feature_request.yml` |
|
||||
| Documentation issues | `.github/ISSUE_TEMPLATE/documentation_issue.yml` |
|
||||
|
||||
## Do NOT
|
||||
|
||||
- Modify CI/CD workflows without explicit approval.
|
||||
- Add new Python dependencies to the core `dependencies` list in `pyproject.toml` without discussion — use optional dependency groups instead.
|
||||
- Commit `.env` files, API keys, or credentials.
|
||||
- Skip pre-commit hooks.
|
||||
- Use npm or yarn in TypeScript packages — this repo uses pnpm exclusively.
|
||||
- Use `require()` for imports in TypeScript — use ES module `import` syntax.
|
||||
- Mix up linter configs: root Python SDK uses line-length 120, Python CLI uses 100, Node CLI uses Biome (not ESLint/Ruff).
|
||||
- Change public APIs without updating documentation in `docs/`.
|
||||
| Issue forms | `.github/ISSUE_TEMPLATE/` |
|
||||
| Contribution gates | [Two gates decide whether your pull request stays open](#two-gates-decide-whether-your-pull-request-stays-open) |
|
||||
| Trust list (vouch) | [`.github/VOUCHED.td`](.github/VOUCHED.td) |
|
||||
| CI/CD, gates, rulesets | [`.github/AGENTS.md`](.github/AGENTS.md) |
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Contribution Conduct
|
||||
|
||||
Mem0 receives more contributions than any maintainer can read line by line. The
|
||||
rules below exist so that the time we do have goes to people who are actually
|
||||
trying to improve the project. They apply to issues, pull requests, discussions,
|
||||
and reviews.
|
||||
|
||||
**Be honest about how the work was produced.** Using an AI tool to find a bug,
|
||||
write a patch, or draft a description is fine and welcome. Not saying so is not.
|
||||
Every issue form and the pull request template ask about AI, and the answer is
|
||||
never held against you. It tells a reviewer where to look. An unanswered review
|
||||
comment on code the author cannot explain is what costs us the afternoon.
|
||||
|
||||
**Do not submit work you have not verified.** A reported bug means you ran it and
|
||||
saw it. A pull request means you ran the tests. Pasting a model's output, a
|
||||
scanner result, or a plausible-looking patch and letting maintainers find out
|
||||
whether it is real moves your work onto someone else's desk. Reports and patches
|
||||
that turn out to be unverified are closed without a detailed response.
|
||||
|
||||
**Do not fabricate evidence.** Invented tracebacks, benchmark numbers you did not
|
||||
measure, reproductions that were never run, tests that assert the implementation
|
||||
back at itself, and descriptions that describe a different change than the diff
|
||||
makes are all treated the same way, regardless of whether a person or a tool
|
||||
produced them.
|
||||
|
||||
**Match your volume to your engagement.** Open changes at the rate you can
|
||||
discuss them. A queue of open pull requests from one author, none of them
|
||||
answered when questioned, is treated as automated submission and handled under
|
||||
enforcement below, whatever the individual diffs look like.
|
||||
|
||||
**Do not press for merges.** Bumping a thread, tagging maintainers repeatedly,
|
||||
asking in Discord or by direct message for a review, and reopening a closed pull
|
||||
request without addressing why it was closed all take attention away from the
|
||||
queue rather than moving your change through it. One polite follow-up after a
|
||||
reasonable wait is fine.
|
||||
|
||||
**Do not contribute for a badge.** Changes made to raise a contribution count,
|
||||
qualify for an event, or pad a profile, whitespace edits, README churn, and
|
||||
mechanical reformatting bundled with nothing else, are closed on sight.
|
||||
|
||||
**Disagreement is fine, and closing is not a verdict.** Our pull request gate
|
||||
closes changes that do not yet link an accepted issue. That is a queue decision,
|
||||
not a judgment of you or your code, and reopening takes about a minute. Argue for
|
||||
your change on its merits; that is a normal and welcome part of contributing.
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, including this
|
||||
repository, our Discord, and our documentation, and also applies when an
|
||||
individual is officially representing the community in public spaces. Examples of
|
||||
representing our community include using an official email address, posting via
|
||||
an official social media account, or acting as an appointed representative at an
|
||||
online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the maintainers at **support@mem0.ai**. All complaints will be
|
||||
reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community, or a first contribution that
|
||||
breaches the Contribution Conduct rules above.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions, including a repeated pattern of unverified or automated submissions
|
||||
after a first warning.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban. At this stage the account may be denounced in `.github/VOUCHED.td`, which
|
||||
means new pull requests are flagged automatically.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
The Contribution Conduct section is specific to this repository.
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][mozilla].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][faq]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[mozilla]: https://github.com/mozilla/inclusion
|
||||
[faq]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
+80
-2
@@ -7,6 +7,12 @@ new features, documentation, examples, and integrations.
|
||||
Mem0 is a polyglot monorepo, and this guide covers contributing to both the
|
||||
**Python SDK** and the **TypeScript SDK** (and the rest of the repository).
|
||||
|
||||
By participating you agree to our [Code of Conduct](./CODE_OF_CONDUCT.md). Its
|
||||
**Contribution Conduct** section is the enforceable form of the rules on this
|
||||
page: disclose AI use, don't submit work you haven't run, don't fabricate
|
||||
reproductions or benchmarks, keep your volume matched to your engagement, and
|
||||
don't press for merges.
|
||||
|
||||
## Before You Start
|
||||
|
||||
### 1. Open an Issue First
|
||||
@@ -23,9 +29,68 @@ in code.
|
||||
- For anything beyond a trivial fix, wait for a maintainer to confirm the approach
|
||||
before starting significant work.
|
||||
|
||||
Every pull request must link to an issue using `Closes #<issue-number>`.
|
||||
A bug report needs a reproduction we can run, the version you are on, and the
|
||||
real output or traceback you saw. Reports without those cannot be acted on and
|
||||
get closed. A feature request needs the problem you hit and the workaround you
|
||||
are living with, not just the API you would like.
|
||||
|
||||
### 2. Sign the Contributor License Agreement (CLA)
|
||||
Every pull request must link to an issue using `Closes #<issue-number>`, and that
|
||||
issue must carry the `accepted` label. A maintainer applies `accepted` once we
|
||||
agree the change is one we want.
|
||||
|
||||
Pull requests that don't link an accepted issue are closed automatically by the
|
||||
[PR Gate](./.github/workflows/pr-gate.yml). **Closed does not mean rejected.** It
|
||||
means the change isn't in the queue yet. Once a maintainer labels the issue the
|
||||
pull request reopens itself, and you don't have to do anything. Documentation-only
|
||||
changes skip the gate entirely.
|
||||
|
||||
A second check looks at who opened the pull request rather than what it changes.
|
||||
If you are not yet in this repo's contributor list
|
||||
([`.github/VOUCHED.td`](./.github/VOUCHED.td)) you get one comment saying so.
|
||||
**Nothing is blocked and there is nothing you need to do.** A maintainer can add
|
||||
you by commenting `!vouch @you` on any issue, which only stops that comment from
|
||||
appearing again. Being on the list is not permission to skip the accepted-issue
|
||||
rule, and being absent from it costs you nothing.
|
||||
|
||||
The list has a negative side too. A maintainer can `!denounce` an account that
|
||||
has been through the
|
||||
[code of conduct](./CODE_OF_CONDUCT.md#contribution-conduct) enforcement process,
|
||||
and pull requests from that account are closed whether or not they link an
|
||||
accepted issue. This is rare, it is never where anyone starts, and it is
|
||||
reversible.
|
||||
|
||||
Security fixes are the one exception, and they don't go through public pull
|
||||
requests at all. Follow the [Security Policy](./SECURITY.md) instead, which uses
|
||||
a private advisory and a private fork so the vulnerability isn't disclosed before
|
||||
the fix ships.
|
||||
|
||||
### 2. Understand Your Code
|
||||
|
||||
**You must be able to explain what your changes do and how they interact with
|
||||
the rest of the codebase without the help of an AI tool.** This is the one rule
|
||||
we will not bend on.
|
||||
|
||||
Using AI to write code is fine. Most of us do. You can build real understanding
|
||||
by interrogating an agent about this codebase until you grasp the edge cases and
|
||||
the blast radius of your change. What is not fine is opening a pull request for
|
||||
a diff you cannot defend in review.
|
||||
|
||||
Disclose it in the pull request template and say what you checked yourself.
|
||||
We ask about the code, not the write-up: using AI to draft the pull request
|
||||
description is fine. We ask because it tells reviewers where to look, not
|
||||
because it counts against you. An honest "an agent wrote this, here is what I
|
||||
verified" is welcome. Silence, followed by a review comment you cannot answer,
|
||||
is what wastes everyone's time.
|
||||
|
||||
Signs your pull request will be closed:
|
||||
|
||||
- Invented APIs, config keys, or providers that don't exist in this repo.
|
||||
- Tests that assert the implementation back at itself rather than the behaviour.
|
||||
- A description that describes a different change than the diff makes.
|
||||
- Sweeping unrelated reformatting bundled with a small fix.
|
||||
- You cannot answer a direct question about your own diff.
|
||||
|
||||
### 3. Sign the Contributor License Agreement (CLA)
|
||||
|
||||
**We cannot accept or merge any pull request until you have signed our Contributor
|
||||
License Agreement (CLA).**
|
||||
@@ -35,6 +100,19 @@ sign. Signing takes less than a minute and only needs to be done once. Pull
|
||||
requests from contributors who have not signed the CLA will be blocked from
|
||||
merging.
|
||||
|
||||
## First Contribution Fast Path
|
||||
|
||||
Fixing a typo or a small docs issue? You don't need the full workflow below.
|
||||
|
||||
1. **Pick something small.** Look for issues labeled `documentation` or `good first issue`, or a typo/broken link you noticed while reading the docs.
|
||||
2. **Branch from `main`** with a name that says what you're fixing, e.g. `docs/fix-quickstart-typo` or `fix/broken-crewai-link`.
|
||||
3. **Make the change, then run only what applies:**
|
||||
- Docs-only change (`docs/**`): preview with `make docs`. If you added or removed an `.mdx` page, run `python scripts/check-llms-txt-coverage.py --write` so `docs/llms.txt` stays in sync.
|
||||
- Code change: run the linter and tests for the package you touched, see [Development Workflow](#development-workflow) below.
|
||||
4. **Open a PR** against `main` with `Closes #<issue-number>` and a one-line description of what you fixed.
|
||||
|
||||
For anything larger than a docs fix or a small bug, follow the full workflow below.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
The two most common contribution targets are the SDKs:
|
||||
|
||||
@@ -11,7 +11,7 @@ install:
|
||||
hatch env create
|
||||
|
||||
install_all:
|
||||
pip install ruff==0.16.0 groq together boto3 litellm ollama chromadb weaviate weaviate-client sentence_transformers vertexai \
|
||||
pip install ruff==0.16.0 groq together boto3 'litellm>=1.83.7,<1.98.0' ollama chromadb weaviate weaviate-client sentence_transformers vertexai \
|
||||
google-generativeai elasticsearch opensearch-py vecs "pinecone<7.0.0" pinecone-text faiss-cpu langchain-community \
|
||||
upstash-vector azure-search-documents langchain-memgraph langchain-neo4j langchain-aws rank-bm25 pymochow pymongo psycopg kuzu databricks-sdk valkey
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ following as you can:
|
||||
- Clear, step-by-step reproduction instructions
|
||||
- The security impact and a proof of concept, if available
|
||||
- Any suggested fix or mitigation
|
||||
- Whether an AI tool was involved in finding or writing up the report
|
||||
|
||||
Reports generated by an AI tool are welcome, but only once you have run the
|
||||
reproduction yourself and confirmed the impact is real. A scan result or model
|
||||
output pasted in without that step is not a vulnerability report, and we close
|
||||
those without a detailed response so we can spend the time on real ones.
|
||||
|
||||
## Response Process
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
# Node CLI (`cli/node/`)
|
||||
|
||||
The `@mem0/cli` package on npm. Commander-based, entry point `mem0`.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm run build # tsup (ESM)
|
||||
pnpm run lint # biome check src/
|
||||
pnpm run lint:fix # biome check --write src/
|
||||
pnpm run typecheck # tsc --noEmit
|
||||
pnpm run test # vitest run
|
||||
pnpm run test:watch
|
||||
pnpm run dev # tsx src/index.ts
|
||||
```
|
||||
|
||||
pnpm only. Never npm, never yarn.
|
||||
|
||||
## Conventions
|
||||
|
||||
> **Biome, not ESLint. vitest, not jest.** `mem0-ts/` uses Prettier + jest and
|
||||
> `integrations/vercel-ai-sdk/` uses ESLint + jest. Running those tools here produces
|
||||
> spurious diffs. Every toolchain in this repo is per-package.
|
||||
|
||||
- **Node 18+** required.
|
||||
- **Build:** tsup, ESM output only.
|
||||
- **Linter and formatter:** Biome, configured in `biome.json`.
|
||||
- **Tests:** vitest.
|
||||
- **TypeScript strict mode.** ES module `import` syntax only, never `require()`.
|
||||
|
||||
Run `pnpm run typecheck` after every change.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Commander + Chalk + ora + cli-table3, and `mem0ai` (npm) for API calls.
|
||||
|
||||
## CI and release
|
||||
|
||||
- CI: `cli-node-ci.yml`, Biome + tsc + vitest + tsup build on Node 20 and 22.
|
||||
- Release: tag prefix `cli-node-v*` dispatches `cli-node-cd.yml`, publishing to npm over OIDC.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
AGENTS.md
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/cli",
|
||||
"version": "0.2.11",
|
||||
"version": "0.2.14",
|
||||
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"tsup": "^8.0.0",
|
||||
"tsx": "^4.7.0",
|
||||
"vite": "^6.0.0",
|
||||
"vitest": "^4.1.0",
|
||||
"vitest": "^4.1.11",
|
||||
"@biomejs/biome": "^1.7.0",
|
||||
"@types/node": "^20.0.0"
|
||||
},
|
||||
|
||||
Generated
+46
-46
@@ -51,8 +51,8 @@ importers:
|
||||
specifier: ^6.0.0
|
||||
version: 6.4.3(@types/node@20.19.37)(tsx@4.21.0)
|
||||
vitest:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.8(@types/node@20.19.37)(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))
|
||||
specifier: ^4.1.11
|
||||
version: 4.1.11(@types/node@20.19.37)(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -439,11 +439,11 @@ packages:
|
||||
'@types/node@20.19.37':
|
||||
resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==}
|
||||
|
||||
'@vitest/expect@4.1.8':
|
||||
resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==}
|
||||
'@vitest/expect@4.1.11':
|
||||
resolution: {integrity: sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==}
|
||||
|
||||
'@vitest/mocker@4.1.8':
|
||||
resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==}
|
||||
'@vitest/mocker@4.1.11':
|
||||
resolution: {integrity: sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==}
|
||||
peerDependencies:
|
||||
msw: ^2.4.9
|
||||
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
@@ -453,20 +453,20 @@ packages:
|
||||
vite:
|
||||
optional: true
|
||||
|
||||
'@vitest/pretty-format@4.1.8':
|
||||
resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==}
|
||||
'@vitest/pretty-format@4.1.11':
|
||||
resolution: {integrity: sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==}
|
||||
|
||||
'@vitest/runner@4.1.8':
|
||||
resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==}
|
||||
'@vitest/runner@4.1.11':
|
||||
resolution: {integrity: sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==}
|
||||
|
||||
'@vitest/snapshot@4.1.8':
|
||||
resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==}
|
||||
'@vitest/snapshot@4.1.11':
|
||||
resolution: {integrity: sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==}
|
||||
|
||||
'@vitest/spy@4.1.8':
|
||||
resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==}
|
||||
'@vitest/spy@4.1.11':
|
||||
resolution: {integrity: sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==}
|
||||
|
||||
'@vitest/utils@4.1.8':
|
||||
resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==}
|
||||
'@vitest/utils@4.1.11':
|
||||
resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==}
|
||||
|
||||
acorn@8.16.0:
|
||||
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
||||
@@ -910,20 +910,20 @@ packages:
|
||||
yaml:
|
||||
optional: true
|
||||
|
||||
vitest@4.1.8:
|
||||
resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==}
|
||||
vitest@4.1.11:
|
||||
resolution: {integrity: sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==}
|
||||
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@opentelemetry/api': ^1.9.0
|
||||
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
|
||||
'@vitest/browser-playwright': 4.1.8
|
||||
'@vitest/browser-preview': 4.1.8
|
||||
'@vitest/browser-webdriverio': 4.1.8
|
||||
'@vitest/coverage-istanbul': 4.1.8
|
||||
'@vitest/coverage-v8': 4.1.8
|
||||
'@vitest/ui': 4.1.8
|
||||
'@vitest/browser-playwright': 4.1.11
|
||||
'@vitest/browser-preview': 4.1.11
|
||||
'@vitest/browser-webdriverio': 4.1.11
|
||||
'@vitest/coverage-istanbul': 4.1.11
|
||||
'@vitest/coverage-v8': 4.1.11
|
||||
'@vitest/ui': 4.1.11
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
@@ -1186,44 +1186,44 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@vitest/expect@4.1.8':
|
||||
'@vitest/expect@4.1.11':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
'@types/chai': 5.2.3
|
||||
'@vitest/spy': 4.1.8
|
||||
'@vitest/utils': 4.1.8
|
||||
'@vitest/spy': 4.1.11
|
||||
'@vitest/utils': 4.1.11
|
||||
chai: 6.2.2
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/mocker@4.1.8(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))':
|
||||
'@vitest/mocker@4.1.11(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.1.8
|
||||
'@vitest/spy': 4.1.11
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 6.4.3(@types/node@20.19.37)(tsx@4.21.0)
|
||||
|
||||
'@vitest/pretty-format@4.1.8':
|
||||
'@vitest/pretty-format@4.1.11':
|
||||
dependencies:
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/runner@4.1.8':
|
||||
'@vitest/runner@4.1.11':
|
||||
dependencies:
|
||||
'@vitest/utils': 4.1.8
|
||||
'@vitest/utils': 4.1.11
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/snapshot@4.1.8':
|
||||
'@vitest/snapshot@4.1.11':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/utils': 4.1.8
|
||||
'@vitest/pretty-format': 4.1.11
|
||||
'@vitest/utils': 4.1.11
|
||||
magic-string: 0.30.21
|
||||
pathe: 2.0.3
|
||||
|
||||
'@vitest/spy@4.1.8': {}
|
||||
'@vitest/spy@4.1.11': {}
|
||||
|
||||
'@vitest/utils@4.1.8':
|
||||
'@vitest/utils@4.1.11':
|
||||
dependencies:
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/pretty-format': 4.1.11
|
||||
convert-source-map: 2.0.0
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
@@ -1627,15 +1627,15 @@ snapshots:
|
||||
fsevents: 2.3.3
|
||||
tsx: 4.21.0
|
||||
|
||||
vitest@4.1.8(@types/node@20.19.37)(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0)):
|
||||
vitest@4.1.11(@types/node@20.19.37)(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.8
|
||||
'@vitest/mocker': 4.1.8(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/runner': 4.1.8
|
||||
'@vitest/snapshot': 4.1.8
|
||||
'@vitest/spy': 4.1.8
|
||||
'@vitest/utils': 4.1.8
|
||||
'@vitest/expect': 4.1.11
|
||||
'@vitest/mocker': 4.1.11(vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0))
|
||||
'@vitest/pretty-format': 4.1.11
|
||||
'@vitest/runner': 4.1.11
|
||||
'@vitest/snapshot': 4.1.11
|
||||
'@vitest/spy': 4.1.11
|
||||
'@vitest/utils': 4.1.11
|
||||
es-module-lexer: 2.1.0
|
||||
expect-type: 1.3.0
|
||||
magic-string: 0.30.21
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface AddOptions {
|
||||
infer?: boolean;
|
||||
expires?: string;
|
||||
customInstructions?: string;
|
||||
agentCustomInstructions?: string;
|
||||
customCategories?: Record<string, string>[];
|
||||
structuredDataSchema?: Record<string, unknown>;
|
||||
timestamp?: number;
|
||||
|
||||
@@ -31,7 +31,8 @@ export class PlatformBackend implements Backend {
|
||||
this.headers = {
|
||||
Authorization: `Token ${config.apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Source": "CLI",
|
||||
"X-Mem0-Client": `mem0-cli-node/${CLI_VERSION}`,
|
||||
"X-Mem0-Client-Language": "node",
|
||||
"X-Mem0-Client-Version": CLI_VERSION,
|
||||
};
|
||||
@@ -153,6 +154,8 @@ export class PlatformBackend implements Backend {
|
||||
if (opts.expires) payload.expiration_date = opts.expires;
|
||||
if (opts.customInstructions)
|
||||
payload.custom_instructions = opts.customInstructions;
|
||||
if (opts.agentCustomInstructions)
|
||||
payload.agent_custom_instructions = opts.agentCustomInstructions;
|
||||
if (opts.customCategories)
|
||||
payload.custom_categories = opts.customCategories;
|
||||
if (opts.structuredDataSchema)
|
||||
|
||||
@@ -53,6 +53,7 @@ export async function cmdAdd(
|
||||
expires?: string;
|
||||
categories?: string;
|
||||
customInstructions?: string;
|
||||
agentCustomInstructions?: string;
|
||||
customCategories?: string;
|
||||
structuredDataSchema?: string;
|
||||
timestamp?: number;
|
||||
@@ -153,6 +154,7 @@ export async function cmdAdd(
|
||||
infer: opts.infer !== false,
|
||||
expires: opts.expires,
|
||||
customInstructions: opts.customInstructions,
|
||||
agentCustomInstructions: opts.agentCustomInstructions,
|
||||
customCategories: customCats,
|
||||
structuredDataSchema: schema,
|
||||
timestamp: opts.timestamp,
|
||||
|
||||
+10
-1
@@ -36,7 +36,16 @@ const COMMAND_GROUPS: { panel: string; commands: string[] }[] = [
|
||||
},
|
||||
{
|
||||
panel: "Management",
|
||||
commands: ["init", "status", "import", "help", "entity", "event", "config"],
|
||||
commands: [
|
||||
"init",
|
||||
"status",
|
||||
"version",
|
||||
"import",
|
||||
"help",
|
||||
"entity",
|
||||
"event",
|
||||
"config",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
+21
-3
@@ -95,6 +95,10 @@ async function getBackendOnly(
|
||||
return (await getBackendAndConfig(apiKey, baseUrl)).backend;
|
||||
}
|
||||
|
||||
function printVersion(): void {
|
||||
console.log(` ${colors.brand("◆ Mem0")} CLI v${CLI_VERSION}`);
|
||||
}
|
||||
|
||||
function checkAgentMode(): boolean {
|
||||
const rootOpts = program.opts();
|
||||
const isAgent = !!(rootOpts.json || rootOpts.agent);
|
||||
@@ -154,7 +158,7 @@ program
|
||||
.enablePositionalOptions()
|
||||
.option("--version", "Show version and exit.")
|
||||
.on("option:version", () => {
|
||||
console.log(` ${colors.brand("◆ Mem0")} CLI v${CLI_VERSION}`);
|
||||
printVersion();
|
||||
process.exit(0);
|
||||
})
|
||||
.option("--json", "Output as JSON for agent/programmatic use.")
|
||||
@@ -328,6 +332,10 @@ program
|
||||
"--custom-instructions <text>",
|
||||
"Custom instructions for fact extraction.",
|
||||
)
|
||||
.option(
|
||||
"--agent-custom-instructions <text>",
|
||||
"Extraction instructions for agent-scoped memories, overriding the project setting.",
|
||||
)
|
||||
.option(
|
||||
"--custom-categories <json>",
|
||||
"Custom categories as a JSON array of {name: description} objects.",
|
||||
@@ -383,7 +391,10 @@ program
|
||||
)
|
||||
.option("--rerank", "Enable reranking (Platform only).", false)
|
||||
.option("--keyword", "Use keyword search.", false)
|
||||
.option("--filter <json>", "Advanced filter expression (JSON).")
|
||||
.option(
|
||||
"--filter <json>",
|
||||
'Advanced filter as JSON: {"AND": [...]} or {"OR": [...]}, e.g. {"AND": [{"categories": {"in": ["work"]}}]}.',
|
||||
)
|
||||
.option("--fields <list>", "Specific fields to return (comma-separated).")
|
||||
.option("--show-expired", "Include expired memories.", false)
|
||||
.option(
|
||||
@@ -400,7 +411,7 @@ program
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
.addHelpText(
|
||||
"after",
|
||||
'\nExamples:\n $ mem0 search "preferences" --user-id alice\n $ mem0 search "tools" -u alice -o json -k 5\n $ echo "preferences" | mem0 search -u alice',
|
||||
'\nExamples:\n $ mem0 search "preferences" --user-id alice\n $ mem0 search "tools" -u alice -o json -k 5\n $ echo "preferences" | mem0 search -u alice\n $ mem0 search "invoices" -u alice --filter \'{"AND": [{"categories": {"in": ["work"]}}]}\'',
|
||||
)
|
||||
.action(async (query, opts) => {
|
||||
let resolvedQuery = query;
|
||||
@@ -819,6 +830,13 @@ program
|
||||
});
|
||||
});
|
||||
|
||||
program
|
||||
.command("version")
|
||||
.description("Show version and exit.")
|
||||
.action(() => {
|
||||
printVersion();
|
||||
});
|
||||
|
||||
program
|
||||
.command("import <filePath>")
|
||||
.description("Import memories from a JSON file.")
|
||||
|
||||
@@ -44,11 +44,17 @@ describe("CLI Integration — help and version", () => {
|
||||
expect(result.stdout).toContain("search");
|
||||
});
|
||||
|
||||
it("prints the version with --version, and has no version subcommand", () => {
|
||||
it("prints the version with --version", () => {
|
||||
const flag = run(["--version"]);
|
||||
expect(flag.exitCode).toBe(0);
|
||||
expect(flag.stdout).toContain("Mem0");
|
||||
expect(run(["version"]).exitCode).not.toBe(0);
|
||||
});
|
||||
|
||||
it("version subcommand output matches --version output byte-for-byte", () => {
|
||||
const flag = run(["--version"]);
|
||||
const cmd = run(["version"]);
|
||||
expect(cmd.exitCode).toBe(0);
|
||||
expect(cmd.stdout).toBe(flag.stdout);
|
||||
});
|
||||
|
||||
it.each([["help", "--json"], ["--json", "help"], ["--agent", "help"]])(
|
||||
@@ -129,6 +135,13 @@ describe("CLI Integration — help and version", () => {
|
||||
expect(result.stdout).toContain("--rerank");
|
||||
});
|
||||
|
||||
it("search help documents the --filter JSON shape with an example", () => {
|
||||
const result = run(["search", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stdout).toContain("AND");
|
||||
expect(result.stdout).toContain("categories");
|
||||
});
|
||||
|
||||
it("list help has --category flag", () => {
|
||||
const result = run(["list", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
@@ -50,6 +50,7 @@ const ADD_MAPPING: Record<string, string[]> = {
|
||||
metadata: ["--metadata"],
|
||||
expiration_date: ["--expires"],
|
||||
custom_instructions: ["--custom-instructions"],
|
||||
agent_custom_instructions: ["--agent-custom-instructions"],
|
||||
custom_categories: ["--custom-categories"],
|
||||
infer: ["--no-infer"],
|
||||
immutable: ["--immutable"],
|
||||
|
||||
@@ -84,6 +84,7 @@ describe("PlatformBackend option-parity payloads (MEM-5893)", () => {
|
||||
metadata: { source: "test" },
|
||||
expires: "2099-01-01",
|
||||
customInstructions: "Extract only preferences.",
|
||||
agentCustomInstructions: "Extract only tool outcomes.",
|
||||
customCategories: [{ prefs: "user preferences" }],
|
||||
structuredDataSchema: { type: "object" },
|
||||
timestamp: 1700000000,
|
||||
@@ -91,6 +92,9 @@ describe("PlatformBackend option-parity payloads (MEM-5893)", () => {
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload.custom_instructions).toBe("Extract only preferences.");
|
||||
expect(payload.agent_custom_instructions).toBe(
|
||||
"Extract only tool outcomes.",
|
||||
);
|
||||
expect(payload.custom_categories).toEqual([{ prefs: "user preferences" }]);
|
||||
expect(payload.structured_data_schema).toEqual({ type: "object" });
|
||||
expect(payload.timestamp).toBe(1700000000);
|
||||
@@ -109,6 +113,7 @@ describe("PlatformBackend option-parity payloads (MEM-5893)", () => {
|
||||
|
||||
const payload = spy.mock.calls[0][2].json;
|
||||
expect(payload).not.toHaveProperty("custom_instructions");
|
||||
expect(payload).not.toHaveProperty("agent_custom_instructions");
|
||||
expect(payload).not.toHaveProperty("custom_categories");
|
||||
expect(payload).not.toHaveProperty("structured_data_schema");
|
||||
expect(payload).not.toHaveProperty("timestamp");
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Python CLI (`cli/python/`)
|
||||
|
||||
The `mem0-cli` package on PyPI. Typer-based, entry point `mem0`.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]" # dev install: ruff + pytest
|
||||
ruff check . # lint
|
||||
ruff format . # format
|
||||
pytest # test
|
||||
hatch build # build
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
> **Line length is 100 here, not 120.** The root Python SDK uses 120. Running the root
|
||||
> `make format` over this directory reformats every file and fails CI. Use the local
|
||||
> `ruff` invocations above.
|
||||
|
||||
- **Python 3.10+.** Not 3.9, unlike the root SDK.
|
||||
- **Ruff** with an extended rule set: `E`, `F`, `I`, `W`, `UP`, `B`, `SIM`, `RUF`.
|
||||
Ignores `E501` (formatter handles it), `B008` (required by Typer's argument defaults),
|
||||
and `SIM108`.
|
||||
- **Ruff format:** double quotes, space indent, `docstring-code-format = true`.
|
||||
- **isort** first-party is `mem0_cli` only.
|
||||
- **pytest** for tests.
|
||||
- Target version pinned to `py310`.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
cli/python/
|
||||
├── src/mem0_cli/ package source (src layout)
|
||||
└── tests/
|
||||
```
|
||||
|
||||
Entry point: `mem0 = "mem0_cli.app:main"`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Typer + Rich + httpx. `mem0ai` is **optional**, exposed through the `[oss]` extra for OSS mode. Do not promote it to a required dependency.
|
||||
|
||||
## CI and release
|
||||
|
||||
- CI: `cli-python-ci.yml`, ruff + pytest + `hatch build` on Python 3.10, 3.11, 3.12.
|
||||
- Release: tag prefix `cli-v*` dispatches `cli-python-cd.yml`, publishing to PyPI over OIDC.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
AGENTS.md
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "mem0-cli"
|
||||
version = "0.2.10"
|
||||
version = "0.2.13"
|
||||
description = "The official CLI for mem0 — the memory layer for AI agents"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
|
||||
|
||||
__version__ = "0.2.10"
|
||||
__version__ = "0.2.13"
|
||||
|
||||
@@ -278,6 +278,11 @@ def add(
|
||||
custom_instructions: str | None = typer.Option(
|
||||
None, "--custom-instructions", help="Custom instructions for fact extraction."
|
||||
),
|
||||
agent_custom_instructions: str | None = typer.Option(
|
||||
None,
|
||||
"--agent-custom-instructions",
|
||||
help="Extraction instructions for agent-scoped memories, overriding the project setting.",
|
||||
),
|
||||
custom_categories: str | None = typer.Option(
|
||||
None,
|
||||
"--custom-categories",
|
||||
@@ -327,6 +332,7 @@ def add(
|
||||
expires=expires,
|
||||
categories=categories,
|
||||
custom_instructions=custom_instructions,
|
||||
agent_custom_instructions=agent_custom_instructions,
|
||||
custom_categories=custom_categories,
|
||||
structured_data_schema=structured_data_schema,
|
||||
timestamp=timestamp,
|
||||
@@ -365,7 +371,11 @@ def search(
|
||||
False, "--keyword", help="Use keyword search.", rich_help_panel="Search"
|
||||
),
|
||||
filter_json: str | None = typer.Option(
|
||||
None, "--filter", help="Advanced filter expression (JSON).", rich_help_panel="Search"
|
||||
None,
|
||||
"--filter",
|
||||
help='Advanced filter as JSON: {"AND": [...]} or {"OR": [...]}, '
|
||||
'e.g. {"AND": [{"categories": {"in": ["work"]}}]}.',
|
||||
rich_help_panel="Search",
|
||||
),
|
||||
fields: str | None = typer.Option(
|
||||
None,
|
||||
@@ -408,6 +418,7 @@ def search(
|
||||
mem0 search "preferences" --user-id alice
|
||||
mem0 search "tools" -u alice -o json -k 5
|
||||
echo "preferences" | mem0 search -u alice
|
||||
mem0 search "invoices" -u alice --filter '{"AND": [{"categories": {"in": ["work"]}}]}'
|
||||
"""
|
||||
from mem0_cli.commands.memory import cmd_search
|
||||
|
||||
@@ -1078,6 +1089,18 @@ def status(
|
||||
)
|
||||
|
||||
|
||||
@app.command(rich_help_panel="Management")
|
||||
def version() -> None:
|
||||
"""Show version and exit.
|
||||
|
||||
Example:
|
||||
mem0 version
|
||||
"""
|
||||
from mem0_cli.commands.utils import cmd_version
|
||||
|
||||
cmd_version()
|
||||
|
||||
|
||||
@app.command("import", rich_help_panel="Management")
|
||||
def import_cmd(
|
||||
file_path: str = typer.Argument(..., help="JSON file to import."),
|
||||
@@ -1139,6 +1162,7 @@ def _build_help_json() -> dict:
|
||||
"--expires": "Expiration date (YYYY-MM-DD).",
|
||||
"--categories": "Not supported on add, use --custom-categories instead.",
|
||||
"--custom-instructions": "Custom instructions for fact extraction.",
|
||||
"--agent-custom-instructions": "Extraction instructions for agent-scoped memories, overriding the project setting.",
|
||||
"--custom-categories": "Custom categories as a JSON array of {name: description} objects.",
|
||||
"--structured-data-schema": "Schema for structured data extraction, as JSON.",
|
||||
"--timestamp": "Unix timestamp for the memory.",
|
||||
@@ -1158,7 +1182,10 @@ def _build_help_json() -> dict:
|
||||
"--threshold": "Minimum similarity score (default: 0.3).",
|
||||
"--rerank": "Enable reranking (Platform only).",
|
||||
"--keyword": "Use keyword search instead of semantic.",
|
||||
"--filter": "Advanced filter expression (JSON).",
|
||||
"--filter": (
|
||||
'Advanced filter as JSON: {"AND": [...]} or {"OR": [...]}, '
|
||||
'e.g. {"AND": [{"categories": {"in": ["work"]}}]}.'
|
||||
),
|
||||
"--fields": "Specific fields to return (comma-separated).",
|
||||
"--show-expired": "Include expired memories.",
|
||||
"--reference-date": "Reference date for relative queries (YYYY-MM-DD or unix timestamp).",
|
||||
|
||||
@@ -26,6 +26,7 @@ class Backend(ABC):
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
custom_instructions: str | None = None,
|
||||
agent_custom_instructions: str | None = None,
|
||||
custom_categories: list[dict] | None = None,
|
||||
structured_data_schema: dict | None = None,
|
||||
timestamp: int | None = None,
|
||||
|
||||
@@ -27,7 +27,8 @@ class PlatformBackend(Backend):
|
||||
headers={
|
||||
"Authorization": f"Token {config.api_key}",
|
||||
"Content-Type": "application/json",
|
||||
"X-Mem0-Source": "cli",
|
||||
"X-Mem0-Source": "CLI",
|
||||
"X-Mem0-Client": f"mem0-cli-python/{__version__}",
|
||||
"X-Mem0-Client-Language": "python",
|
||||
"X-Mem0-Client-Version": __version__,
|
||||
},
|
||||
@@ -88,6 +89,7 @@ class PlatformBackend(Backend):
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
custom_instructions: str | None = None,
|
||||
agent_custom_instructions: str | None = None,
|
||||
custom_categories: list[dict] | None = None,
|
||||
structured_data_schema: dict | None = None,
|
||||
timestamp: int | None = None,
|
||||
@@ -117,6 +119,8 @@ class PlatformBackend(Backend):
|
||||
payload["expiration_date"] = expires
|
||||
if custom_instructions:
|
||||
payload["custom_instructions"] = custom_instructions
|
||||
if agent_custom_instructions:
|
||||
payload["agent_custom_instructions"] = agent_custom_instructions
|
||||
if custom_categories:
|
||||
payload["custom_categories"] = custom_categories
|
||||
if structured_data_schema:
|
||||
|
||||
@@ -77,6 +77,7 @@ def cmd_add(
|
||||
expires: str | None,
|
||||
categories: str | None,
|
||||
custom_instructions: str | None = None,
|
||||
agent_custom_instructions: str | None = None,
|
||||
custom_categories: str | None = None,
|
||||
structured_data_schema: str | None = None,
|
||||
timestamp: int | None = None,
|
||||
@@ -166,6 +167,7 @@ def cmd_add(
|
||||
infer=not no_infer,
|
||||
expires=expires,
|
||||
custom_instructions=custom_instructions,
|
||||
agent_custom_instructions=agent_custom_instructions,
|
||||
custom_categories=custom_cats,
|
||||
structured_data_schema=schema,
|
||||
timestamp=timestamp,
|
||||
|
||||
@@ -91,7 +91,12 @@ class TestCLIIntegration:
|
||||
flag = _run(["--version"])
|
||||
assert flag.returncode == 0
|
||||
assert __version__ in flag.stdout
|
||||
assert _run(["version"]).returncode != 0
|
||||
|
||||
def test_version_subcommand_matches_flag_byte_for_byte(self):
|
||||
flag = _run(["--version"])
|
||||
cmd = _run(["version"])
|
||||
assert cmd.returncode == 0
|
||||
assert cmd.stdout == flag.stdout
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
@@ -127,6 +132,12 @@ class TestCLIIntegration:
|
||||
assert result.returncode == 0
|
||||
assert "top-k" in result.stdout
|
||||
|
||||
def test_search_help_documents_filter_json_shape(self):
|
||||
result = _run(["search", "--help"])
|
||||
assert result.returncode == 0
|
||||
assert "AND" in result.stdout
|
||||
assert "categories" in result.stdout
|
||||
|
||||
def test_list_help(self):
|
||||
result = _run(["list", "--help"])
|
||||
assert result.returncode == 0
|
||||
|
||||
@@ -38,6 +38,7 @@ ADD_MAPPING: dict[str, list[str]] = {
|
||||
"metadata": ["metadata"],
|
||||
"expiration_date": ["expires"],
|
||||
"custom_instructions": ["custom_instructions"],
|
||||
"agent_custom_instructions": ["agent_custom_instructions"],
|
||||
"custom_categories": ["custom_categories"],
|
||||
"infer": ["no_infer"],
|
||||
"immutable": ["immutable"],
|
||||
|
||||
@@ -22,12 +22,14 @@ class TestAddOptions:
|
||||
metadata={"source": "test"},
|
||||
expires="2099-01-01",
|
||||
custom_instructions="Extract only preferences.",
|
||||
agent_custom_instructions="Extract only tool outcomes.",
|
||||
custom_categories=[{"prefs": "user preferences"}],
|
||||
structured_data_schema={"type": "object"},
|
||||
timestamp=1700000000,
|
||||
)
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert payload["custom_instructions"] == "Extract only preferences."
|
||||
assert payload["agent_custom_instructions"] == "Extract only tool outcomes."
|
||||
assert payload["custom_categories"] == [{"prefs": "user preferences"}]
|
||||
assert payload["structured_data_schema"] == {"type": "object"}
|
||||
assert payload["timestamp"] == 1700000000
|
||||
@@ -40,6 +42,7 @@ class TestAddOptions:
|
||||
backend.add(content="hello", user_id="alice")
|
||||
payload = mock_request.call_args.kwargs["json"]
|
||||
assert "custom_instructions" not in payload
|
||||
assert "agent_custom_instructions" not in payload
|
||||
assert "custom_categories" not in payload
|
||||
assert "structured_data_schema" not in payload
|
||||
assert "timestamp" not in payload
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Documentation (`docs/`)
|
||||
|
||||
Mintlify site published at https://docs.mem0.ai.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
make docs # from repo root
|
||||
cd docs && mintlify dev
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
| Path | Contents |
|
||||
|------|----------|
|
||||
| `api-reference/` | Platform REST endpoints |
|
||||
| `open-source/` | Self-hosted SDK guides |
|
||||
| `platform/` | Hosted platform guides |
|
||||
| `integrations/` | One page per integration |
|
||||
| `core-concepts/` | Memory model, graph memory, scoping |
|
||||
| `cookbooks/` | End-to-end recipes |
|
||||
| `contributing/` | Contributor guides |
|
||||
| `docs.json` | Navigation tree |
|
||||
| `openapi.json` | Platform API spec |
|
||||
| `llms.txt` | Scope-tagged index for agents |
|
||||
|
||||
## Adding a page
|
||||
|
||||
Every new `.mdx` page needs three things, or CI fails:
|
||||
|
||||
1. The page itself under the right section.
|
||||
2. A navigation entry in `docs.json`.
|
||||
3. A line in `llms.txt` with a scope tag (`[Platform]`, `[OSS]`, or `[Both]`) and a description that starts with `Use when ...`.
|
||||
|
||||
`docs-llms-txt-check.yml` runs on every PR touching `docs/**/*.mdx` and **blocks the merge** when `llms.txt` is out of sync. To fix:
|
||||
|
||||
```bash
|
||||
python scripts/check-llms-txt-coverage.py --write
|
||||
```
|
||||
|
||||
That scaffolds placeholders under `## Unclassified - needs triage`. Then replace each `[TODO: ...]` tag, rewrite the descriptions as `Use when ...`, move entries into the correct section, and delete the triage heading once it is empty.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Frontmatter needs `title`, `description`, and usually `icon`.
|
||||
- Mintlify components (`<Note>`, `<Card>`, `<Tabs>`, `<CodeGroup>`) are available; prefer them over raw HTML.
|
||||
- Code samples must be runnable. If a sample calls a public SDK method, it has to match the real signature.
|
||||
- Documentation-only PRs are exempt from the `accepted`-issue requirement in the PR gate, but not from the CLA.
|
||||
- Any change to a public SDK signature has to update the matching page here in the same PR.
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
AGENTS.md
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "Overview"
|
||||
title: "API Reference Overview"
|
||||
sidebarTitle: "Overview"
|
||||
icon: "terminal"
|
||||
iconType: "solid"
|
||||
description: "REST APIs for memory management, search, and entity operations"
|
||||
@@ -10,7 +11,7 @@ description: "REST APIs for memory management, search, and entity operations"
|
||||
Mem0 provides a comprehensive REST API for integrating advanced memory capabilities into your applications. Create, search, update, and manage memories across users, agents, and custom entities with simple HTTP requests.
|
||||
|
||||
<Info>
|
||||
**Quick start:** Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=api-reference" rel="nofollow">Mem0 Dashboard</a> and make your first memory operation in minutes.
|
||||
**Quick start:** Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=api-reference">Mem0 Dashboard</a> and make your first memory operation in minutes.
|
||||
</Info>
|
||||
|
||||
---
|
||||
@@ -87,7 +88,7 @@ All API requests require authentication using Token-based authentication. Includ
|
||||
Authorization: Token <your-api-key>
|
||||
```
|
||||
|
||||
Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=api-reference" rel="nofollow">Mem0 Dashboard</a>.
|
||||
Get your API key from the <a href="https://app.mem0.ai/dashboard/api-keys?utm_source=oss&utm_medium=api-reference">Mem0 Dashboard</a>.
|
||||
|
||||
<Warning>
|
||||
**Keep your API key secure.** Never expose it in client-side code or public repositories. Use environment variables and server-side requests only.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Preview Dream Scope"
|
||||
description: "A no-write preview of the scope Dream synthesis would analyze for a project."
|
||||
openapi: "post /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/preview/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get Dream Activity"
|
||||
description: "Supersede/merge activity feed for a project, newest first (keyset-paginated)."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/activity/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get Dream Configuration"
|
||||
description: "Retrieve a project's Dream (memory synthesis) configuration and plan entitlements."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/config/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get a Synthesized Memory's Sources"
|
||||
description: "The source memories a synthesized (pattern) memory was distilled from."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/memory/{memory_id}/sources/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get Memories in a Dream Run"
|
||||
description: "Keyset page of the synthesized memories within a single synthesis run."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/runs/{run_id}/memories/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get Dream Synthesis Runs"
|
||||
description: "Synthesis activity grouped per run, newest first (keyset-paginated)."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/runs/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Get Dream Stats"
|
||||
description: "Lifecycle and synthesis counts for a project, plus reflection freshness."
|
||||
openapi: "get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/stats/"
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Update Dream Configuration"
|
||||
description: "Enable or disable Synthesis (reflection) for a project, or change the reflection mode."
|
||||
openapi: "patch /api/v1/orgs/organizations/{org_id}/projects/{project_id}/dream/config/"
|
||||
---
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Delete Memory'
|
||||
title: "Delete Memory API Endpoint"
|
||||
sidebarTitle: "Delete Memory"
|
||||
description: "Delete a single memory by its unique memory ID from the Mem0 platform using the DELETE endpoint."
|
||||
openapi: delete /v1/memories/{memory_id}/
|
||||
---
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Update Memory'
|
||||
title: "Update Memory API Endpoint"
|
||||
sidebarTitle: "Update Memory"
|
||||
description: "Update the content, metadata, timestamp, or expiration date of a single memory by its unique ID using the PUT endpoint."
|
||||
openapi: put /v1/memories/{memory_id}/
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Add Member'
|
||||
title: "Add Organization Member API Endpoint"
|
||||
sidebarTitle: "Add Member"
|
||||
description: "Add a new member to an organization with a specified role such as READER or OWNER access level."
|
||||
openapi: post /api/v1/orgs/organizations/{org_id}/members/
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Get Members'
|
||||
title: "Get Organization Members API Endpoint"
|
||||
sidebarTitle: "Get Members"
|
||||
description: "Retrieve a list of all members belonging to a specific organization on the Mem0 platform."
|
||||
openapi: get /api/v1/orgs/organizations/{org_id}/members/
|
||||
---
|
||||
@@ -95,6 +95,12 @@ client.project.update(
|
||||
custom_instructions="..."
|
||||
)
|
||||
|
||||
# Separate extraction instructions for agent-scoped memories
|
||||
# (see /platform/features/custom-instructions)
|
||||
client.project.update(
|
||||
agent_custom_instructions="..."
|
||||
)
|
||||
|
||||
# Use the input language for memory storage and retrieval
|
||||
client.project.update(multilingual=True)
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Generate Profiles'
|
||||
description: "Start one generation: sample a few entities, or build one for a single entity."
|
||||
openapi: post /v2/profiles/jobs/
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Get Generation Job'
|
||||
description: "Read the progress of a generation, and whether it finished."
|
||||
openapi: get /v2/profiles/jobs/{job_id}/
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Get Profile Settings'
|
||||
description: "Retrieve the profile schema, custom instructions, and enabled flag for the current project."
|
||||
openapi: get /v2/profiles/settings/
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Get Profile'
|
||||
description: "Retrieve the structured profile for a user, with a status describing whether generation has completed."
|
||||
openapi: get /v2/entities/{entity_type}/{entity_id}/profile/
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Update Profile Settings'
|
||||
description: "Set the JSON Schema, custom instructions, or enabled flag that control profile generation for the project."
|
||||
openapi: post /v2/profiles/settings/
|
||||
---
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Add Member'
|
||||
title: "Add Project Member API Endpoint"
|
||||
sidebarTitle: "Add Member"
|
||||
description: "Add a new member to a project with a specified role such as READER or OWNER access level."
|
||||
openapi: post /api/v1/orgs/organizations/{org_id}/projects/{project_id}/members/
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: 'Get Members'
|
||||
title: "Get Project Members API Endpoint"
|
||||
sidebarTitle: "Get Members"
|
||||
description: "Retrieve a list of all members belonging to a specific project on the Mem0 platform."
|
||||
openapi: get /api/v1/orgs/organizations/{org_id}/projects/{project_id}/members/
|
||||
---
|
||||
@@ -4,6 +4,55 @@ description: "Major product launches, headline features, and milestones for Mem0
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Update label="2026-08-24" description="DeepSeek Harness plugin">
|
||||
|
||||
**DeepSeek Harness: Mem0 as a Native Cordis Plugin**
|
||||
|
||||
The DeepSeek Harness agent forgets everything between sessions. [`@mem0/deepseek-plugin`](https://www.npmjs.com/package/@mem0/deepseek-plugin) gives it two Mem0-backed tools, so recall and writes persist across runs against the same memory bank you already use from Claude Code, Codex, and every other connected agent.
|
||||
|
||||
- **Two agent-callable tools:** `search_memory` recalls facts relevant to a query, `add_memory` stores a fact for future sessions. Both accept per-call `userId` / `agentId` / `runId` scope overrides.
|
||||
- **Native Cordis lifecycle:** The plugin declares `inject = ['tools']` so it waits for the harness tool registry, then registers through `ctx.tools.register()`. Unmounting the plugin removes the tools automatically.
|
||||
- **Managed backend, not a memory file:** Server-side extraction, semantic dedup, and conflict resolution, rather than a Markdown file the agent has to maintain itself.
|
||||
- **Config:** `userId` is required, `apiKey` defaults to `$MEM0_API_KEY`, and `host` optionally targets a dedicated Mem0 Platform base URL.
|
||||
|
||||
See [DeepSeek Harness](/integrations/deepseek-plugin) for setup and [SDK & Tools](/changelog/sdk) for PR links.
|
||||
|
||||
<Note>
|
||||
Developer preview. Auto-capture and auto-recall, where memory reaches the context with no explicit tool call, are planned but not yet built.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="Strands Agents integration">
|
||||
|
||||
**Strands Agents: Mem0 as a Native MemoryStore**
|
||||
|
||||
[`mem0-strands`](https://pypi.org/project/mem0-strands/) plugs Mem0 into AWS's [Strands Agents](https://strandsagents.com/) SDK as a native `MemoryStore`, so recall and writes happen inside the agent loop rather than as tool calls the model has to remember to make.
|
||||
|
||||
- **Automatic recall:** The `MemoryManager` drives the store on every turn, searching Mem0 and injecting the results into the prompt with no tool call required.
|
||||
- **Server-side extraction:** Because the store implements `add_messages`, enabling extraction routes raw conversation turns straight to Mem0's extraction pipeline, skipping the extra client-side model call needed to distill facts first.
|
||||
- **Hosted or self-hosted:** An API key targets the hosted Mem0 Platform; a config dict targets self-hosted Mem0 OSS.
|
||||
- **Entity scoping:** Accepts `user_id`, `agent_id`, `run_id`, and `app_id`, with at least one required and invalid combinations rejected at construction rather than on the first write.
|
||||
|
||||
See [Strands Agents](/integrations/strands) for setup and [SDK & Tools](/changelog/sdk) for PR links.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-13" description="Kimi Code plugin">
|
||||
|
||||
**Kimi Code: Mem0 Joins the Editor Plugin Family**
|
||||
|
||||
The shared Mem0 editor plugin now covers Kimi Code alongside Claude Code, Cursor, Codex, and Antigravity, running on the same scripts, skills, and memory bank, so context written in one editor is available in the others.
|
||||
|
||||
- **Hosted MCP server:** Registers `https://mcp.mem0.ai/mcp/`, authenticated with `MEM0_API_KEY` as a bearer token.
|
||||
- **Automatic capture and recall:** SessionStart loads context through the `context-loader` skill, and hooks on prompt submit, file reads, Bash output, stop, and pre-compact capture and inject memory without an explicit tool call.
|
||||
- **Guardrails:** Direct `Write` / `Edit` / `MultiEdit` to memory files is blocked, and metadata defaults are enforced on every Mem0 MCP tool call.
|
||||
- **Kimi hook adapter:** A shim normalizes Kimi Code's hook contract to the shape the shared scripts already expect, resolving the real project directory and translating the differing prompt, tool-output, and MCP tool-name fields.
|
||||
|
||||
See [SDK & Tools](/changelog/sdk) for version details and PR links.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-30" description="n8n and Zapier integrations">
|
||||
|
||||
**Workflow Automation: Mem0 Memory in n8n and Zapier**
|
||||
|
||||
+759
-3
@@ -7,6 +7,94 @@ mode: "wide"
|
||||
<Tabs>
|
||||
<Tab title="Python">
|
||||
|
||||
<Update label="2026-09-25" description="v2.2.1">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** `add()` (`Memory` and `AsyncMemory`) no longer reports records the vector store rejected as successful `ADD` events. Only records that were actually inserted are written to history, entity-linked, and returned. If none of the extracted memories could be inserted, `add()` now raises `VectorStoreError` instead of returning memories that were never stored ([#7066](https://github.com/mem0ai/mem0/pull/7066))
|
||||
- **Core:** Restore the context-manager protocol on `Memory` (`with Memory() as m:`) and `AsyncMemory` (`async with AsyncMemory() as m:`), which closes the instance on exit ([#7354](https://github.com/mem0ai/mem0/pull/7354))
|
||||
- **LLMs:** The AWS Bedrock Anthropic path now returns the first Converse content block that carries text instead of always reading `content[0]`. Claude reasoning models can emit a `reasoningContent` block before the text block, which previously made the call fail with a `KeyError` ([#6369](https://github.com/mem0ai/mem0/pull/6369))
|
||||
- **Vector Stores:** Turbopuffer filters now apply every operator (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`). Only `gte` and `lte` were read before, so any other operator was silently dropped and the query returned unfiltered results. An unsupported operator now raises `ValueError` ([#6564](https://github.com/mem0ai/mem0/pull/6564))
|
||||
- **Vector Stores:** Turbopuffer `search()` scores now respect `distance_metric`. With `euclidean_squared`, the unbounded squared distance maps to `1 / (1 + distance)` instead of `1 - distance`, which went negative and inverted ranking for any distance above 1 ([#6559](https://github.com/mem0ai/mem0/pull/6559))
|
||||
- **Vector Stores:** S3 Vectors `search()` scores are now metric-aware. With `euclidean`, the distance maps to `1 / (1 + distance)` instead of `max(0, 1 - distance)`, which collapsed most scores to 0 ([#6547](https://github.com/mem0ai/mem0/pull/6547))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-23" description="v2.2.0">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add User Profiles to `MemoryClient` and `AsyncMemoryClient`: `get_profile()`, `generate_profile()`, `get_profile_settings()`, `update_profile_settings()`, `sample_profiles()`, and `get_profile_job()`. A profile is a structured, always-current JSON summary of one user, shaped by a JSON Schema you configure per project and filled by an LLM from that user's memories. Generation is asynchronous. Every job POST carries an `Idempotency-Key`; to retry a lost request without starting a second job, pass the same `idempotency_key` on each attempt ([#7340](https://github.com/mem0ai/mem0/pull/7340))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Vector Stores:** Guard against `None` timestamps in the Valkey vector store's `insert()` and `update()` paths. `created_at` and `updated_at` fields that were present in the payload but set to `None` previously passed the `"created_at" not in payload` / `"updated_at" in payload` checks and raised `TypeError` when `datetime.fromisoformat()` received `None`. Both paths now use `.get()` with a truthiness check so `None` values fall through to the default, matching the Redis provider's behavior ([#6993](https://github.com/mem0ai/mem0/pull/6993))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="v2.1.0">
|
||||
|
||||
**Improvements:**
|
||||
- **Client:** Requests now carry three surface-identity headers so the platform can tell which product made a call. `X-Mem0-Source` names the surface and `X-Application` the host app it runs inside, both set-once so a wrapper that already declared its identity keeps it. `X-Mem0-Client` is append-only and carries `name/version` per layer, outermost first, so a plugin calling this SDK reports the whole chain rather than only the last speaker. `MEM0_SOURCE`, `MEM0_APPLICATION` and `MEM0_CLIENT_STACK` set them from the environment for wrappers that cannot pass options ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
- **Client:** The client stack is bounded by dropping whole entries rather than slicing characters, and this SDK's own entry is the reserved one. Truncating the joined string could sever an identifier mid-name and the platform parsed the fragment as a real client ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-02" description="v2.0.20">
|
||||
|
||||
**Improvements:**
|
||||
- **OSS notices:** Notice configuration now comes from a static, cacheable repository file with a bundled disabled fallback and deterministic rollout assignment, instead of calling PostHog's feature-flag evaluation API. This keeps notices fail-safe when the remote config is unavailable and removes the PostHog feature-flag request from notice evaluation ([#7185](https://github.com/mem0ai/mem0/pull/7185))
|
||||
- **Vector Stores:** `RedisDBConfig` now uses Pydantic's native `extra="forbid"` handling for unknown fields instead of a custom model validator, preserving strict validation while returning standard Pydantic errors ([#7089](https://github.com/mem0ai/mem0/pull/7089))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="v2.0.19">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Embeddings:** `HuggingFaceEmbedding` now falls back to the `HUGGINGFACE_API_KEY` env var, then a placeholder key, when `huggingface_base_url` is set and no `api_key` is configured. The OpenAI-compatible client used to talk to TEI endpoints raises at construction when no key resolves at all, so a TEI deployment that doesn't require a real key previously failed to initialize ([#6947](https://github.com/mem0ai/mem0/pull/6947))
|
||||
- **Core:** `remove_code_blocks()` now accepts list-shaped content (a sequence of `{"text": ...}` blocks, as some agent frameworks pass) by joining each block's text before stripping code fences, instead of raising `AttributeError` from calling `.strip()` on a list ([#6947](https://github.com/mem0ai/mem0/pull/6947))
|
||||
- **Core:** `create_procedural_memory()` (`Memory` and `AsyncMemory`) now raises a clear `ValueError` when the LLM returns no content for the summary, instead of continuing with empty content that surfaced as a confusing error further down the call ([#6947](https://github.com/mem0ai/mem0/pull/6947))
|
||||
- **Proxy:** `mem0.proxy` no longer auto-installs `litellm` via a `pip install` subprocess when the import fails; it now raises `ImportError` with instructions to install it yourself. The auto-install could hang or fail silently in restricted environments and ran an unreviewed install on the caller's behalf ([#6947](https://github.com/mem0ai/mem0/pull/6947))
|
||||
- **Client:** `get_all()` (sync and async) now sends `page` and `page_size` as independent query params instead of requiring both to be set before either was sent. Passing only `page_size` without `page` previously had it silently dropped, so results came back at the server's default page size ([#6900](https://github.com/mem0ai/mem0/pull/6900))
|
||||
- **LLMs:** Add `provider_override` to `AWSBedrockConfig`, an explicit provider name (for example `"anthropic"`) for when `model` is an application inference profile ARN whose opaque ID has no provider substring for `extract_provider()` to detect. Without it, those ARNs raised `ValueError: Unable to determine provider` ([#6899](https://github.com/mem0ai/mem0/pull/6899))
|
||||
- **LLMs:** `VllmConfig` now falls back to the `VLLM_BASE_URL` env var when `vllm_base_url` isn't passed explicitly. The default was filled in before the env var was ever checked, so `VLLM_BASE_URL` was silently ignored ([#6897](https://github.com/mem0ai/mem0/pull/6897))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-11" description="v2.0.18">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Percent-escape `%`, `&`, and `=` in `user_id`, `agent_id`, and `run_id` when building the session scope key for the recent-conversation buffer, so the key stays unambiguous for ids containing those characters. Ordinary ids keep their existing key; an id already containing `%`, `&`, or `=` maps to a new key, so its buffer starts empty once and refills on the next `add()`. Stored memories are unaffected ([#6892](https://github.com/mem0ai/mem0/pull/6892))
|
||||
- **Vector Stores:** Raise `ValueError` when a PGVector `in`/`nin` filter value is not a list. A string value was previously iterated character by character into the generated `= ANY(...)` array (so `{"user_id": {"in": "alice"}}` matched `a`, `l`, `i`, `c`, `e`), and a non-iterable value raised a bare `TypeError` from deep inside filter building ([#6879](https://github.com/mem0ai/mem0/pull/6879))
|
||||
- **Vector Stores:** Reject `index_accuracy=0` in the Oracle AI Vector Search config. The range check sat behind a truthiness test, so `0` skipped validation entirely and was passed through to `WITH TARGET ACCURACY 0` instead of raising ([#6848](https://github.com/mem0ai/mem0/pull/6848))
|
||||
- **Vector Stores:** Close the Oracle connection or pool that Mem0 opened when initialization fails. A client version check, a database version check, or a `create_col()` error previously propagated with the connection still open, leaking it for the life of the process. A caller-supplied `client` is left untouched ([#6839](https://github.com/mem0ai/mem0/pull/6839))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-05" description="v2.0.17">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add `agent_custom_instructions` to `project.update()`/`update_project()` (sync and async) and to the `ProjectUpdateOptions` and `AddMemoryOptions` typed models. It sets a second extraction instruction set that applies only to agent-scoped memories: an add passing `agent_id` without `user_id` uses it, one passing both splits by attribution, and while it is unset `custom_instructions` continues to apply to every memory ([#6809](https://github.com/mem0ai/mem0/pull/6809))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="v2.0.16">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add `reference_date`, `latest_only`, and `keyword_search` to `SearchMemoryOptions`, and `latest_only` to `GetAllMemoryOptions`, keeping the Python client's typed options in sync with the Platform API and the CLIs ([#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Stop `add()` metadata from setting a memory's identity scope. `_build_filters_and_metadata()` now strips `user_id`, `agent_id`, `run_id`, and `actor_id` from caller-supplied `metadata` before building the creation template, so metadata can no longer place a memory into a scope that was never passed through the entity params ([#6656](https://github.com/mem0ai/mem0/pull/6656))
|
||||
- **Vector Stores:** Validate Upstash filter keys and values in `search()`, `keyword_search()`, and `list()`. Filter keys must match a safe identifier pattern, values must be `str`/`int`/`float`/`bool`, and string values containing a double quote or backslash are now rejected instead of being interpolated unescaped into the generated query string ([#5981](https://github.com/mem0ai/mem0/pull/5981))
|
||||
- **Embeddings:** `FastEmbedEmbedding.embed()` now converts its result with `.tolist()` before returning, so callers get a plain `List[float]` instead of a numpy array ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Embeddings:** `HuggingFaceEmbedding` now passes `api_key` to the OpenAI-compatible client when `huggingface_base_url` is set. The configured key was previously dropped, so the client fell back to `OPENAI_API_KEY` from the environment or raised `OpenAIError` at construction when that was unset ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Embeddings:** Replace Ollama's interactive `pip install` prompt on import with a plain `ImportError`. Importing `mem0.embeddings.ollama` without the `ollama` package previously blocked on stdin and then called `sys.exit(1)`, killing the host process instead of raising ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Core:** `remove_code_blocks()` now returns an empty string for `None` input instead of raising `AttributeError` ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Core:** `parse_vision_messages()` now chains the original exception (`raise ... from e`) when an image download fails, so the root cause is preserved in the traceback ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Core:** `process_telemetry_filters(None)` now returns `([], {})`, matching the two-value tuple every caller unpacks, instead of `{}` ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Core:** `LlmFactory.create()` no longer mutates the caller's config dict in place via `.update(kwargs)`; the merge now builds a new dict ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Rerankers:** The Cohere, HuggingFace, SentenceTransformer, and Zero Entropy rerankers' failure-fallback path no longer mutates the caller's document dicts in place when stamping `rerank_score`; it now falls back on copies ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
- **Vector Stores:** Remove `logging.basicConfig()` calls from the MongoDB and Vertex AI Vector Search providers, so selecting either provider no longer reconfigures the host application's root logger as a side effect ([#6770](https://github.com/mem0ai/mem0/pull/6770))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-01" description="v2.0.15">
|
||||
|
||||
**Bug Fixes:**
|
||||
@@ -116,7 +204,7 @@ mode: "wide"
|
||||
<Update label="2026-06-24" description="v2.0.8">
|
||||
|
||||
**New Features:**
|
||||
- **Embeddings:** Add native `embed_batch` to five embedders: LM Studio, Together, HuggingFace, Vertex AI, and Google GenAI: for batched embedding requests ([#5609](https://github.com/mem0ai/mem0/pull/5609))
|
||||
- **Embeddings:** Add native `embed_batch` to five embedders for batched embedding requests: LM Studio, Together, HuggingFace, Vertex AI, and Google GenAI ([#5609](https://github.com/mem0ai/mem0/pull/5609))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Guard against malformed `image_url` entries in `parse_vision_messages` to prevent crashes ([#5631](https://github.com/mem0ai/mem0/pull/5631))
|
||||
@@ -906,7 +994,7 @@ See the [OSS v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-
|
||||
**New Features:**
|
||||
- **OpenMemory:** Added OpenMemory support
|
||||
- **Neo4j:** Added weights to Neo4j model
|
||||
- **AWS:** Added support for Opsearch Serverless
|
||||
- **AWS:** Added support for OpenSearch Serverless
|
||||
- **Examples:** Added ElizaOS Example
|
||||
|
||||
**Improvements:**
|
||||
@@ -1169,6 +1257,89 @@ See the [OSS v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-
|
||||
|
||||
<Tab title="TypeScript">
|
||||
|
||||
<Update label="2026-09-25" description="v3.3.1">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Config (OSS):** `ConfigManager` no longer injects OpenAI's default `baseURL` and `model` into non-OpenAI LLM providers. The defaults now apply only to `openai` and `openai_structured`, so a DeepSeek, xAI, or other provider config without an explicit `baseURL` or `model` falls back to that provider's own defaults and env vars (`DEEPSEEK_API_BASE`, `XAI_API_BASE`, ...) instead of pointing at OpenAI with an OpenAI model name ([#7350](https://github.com/mem0ai/mem0/pull/7350))
|
||||
- **Vector Stores:** Turbopuffer filters now apply every operator (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`). Only the range operators were read before, so `eq`, `ne`, `in`, and `nin` were silently dropped. A `"*"` value now matches anything instead of nothing, an array value is treated as `in`, and an unsupported operator throws ([#6578](https://github.com/mem0ai/mem0/pull/6578))
|
||||
- **Vector Stores:** Turbopuffer `search()` with `euclidean_squared` now maps the unbounded squared distance to `1 / (1 + distance)` instead of `1 - distance`, which went negative and inverted ranking for any distance above 1 ([#6580](https://github.com/mem0ai/mem0/pull/6580))
|
||||
- **Packaging:** `pg`, `@types/pg`, and `natural` are now optional peer dependencies, and `pg` / `@types/pg` accept caret ranges instead of the exact `8.11.3` / `8.11.0` pins, so installing `mem0ai` no longer pulls in `pg` or conflicts with an app's own `pg` version. The PGVector store now imports `pg` only when it is used, so install it alongside `mem0ai` (`npm install pg`) if you use that store. `@types/jest` moved from peer dependencies to dev dependencies ([#7450](https://github.com/mem0ai/mem0/pull/7450))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-23" description="v3.3.0">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add User Profiles to `MemoryClient`: `getProfile()`, `generateProfile()`, `getProfileSettings()`, `updateProfileSettings()`, `sampleProfiles()`, and `getProfileJob()`. A profile is a structured, always-current JSON summary of one user, shaped by a JSON Schema you configure per project and filled by an LLM from that user's memories. Generation is asynchronous. Every job POST carries an `Idempotency-Key`; to retry a lost request without starting a second job, pass the same `idempotencyKey` on each attempt ([#7340](https://github.com/mem0ai/mem0/pull/7340))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="v3.2.0">
|
||||
|
||||
**Improvements:**
|
||||
- **Client:** Requests now carry `X-Mem0-Source`, `X-Application` and `X-Mem0-Client`, matching the Python SDK. The first two are set-once so an outer wrapper keeps its identity; the third is append-only and reports the whole layer chain. Read from `MEM0_SOURCE`, `MEM0_APPLICATION` and `MEM0_CLIENT_STACK` when set ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
- **Client:** The SDK version in `X-Mem0-Client` is injected at build time rather than hardcoded, so it cannot go stale at the next release ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-02" description="v3.1.8">
|
||||
|
||||
**Improvements:**
|
||||
- **OSS notices:** Notice configuration now comes from a static, cacheable repository file with a bundled disabled fallback and deterministic rollout assignment, instead of calling PostHog's feature-flag evaluation API. This keeps notices fail-safe when the remote config is unavailable and removes the PostHog feature-flag request from notice evaluation ([#7185](https://github.com/mem0ai/mem0/pull/7185))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="v3.1.7">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Vector Stores:** Redis and Valkey `search()` / `get()` / `list()` now preserve `agent_id`, `run_id`, and `user_id` as snake_case in the returned payload. The shared payload formatter camelCased every key including those three identity fields, so entity ids came back as `agentId` / `runId` / `userId`, inconsistent with every other vector store ([#6902](https://github.com/mem0ai/mem0/pull/6902))
|
||||
- **Memory (OSS):** Embedding-cache lookups now use `Object.prototype.hasOwnProperty.call()` instead of the `in` operator or a falsy `||` check. Memory text matching an inherited `Object.prototype` property name (`constructor`, `toString`, and similar) previously short-circuited the lookup and resolved to that inherited value instead of computing a real embedding, silently corrupting the stored vector ([#6903](https://github.com/mem0ai/mem0/pull/6903))
|
||||
- **Client:** `getAll()` now sends `page` and `pageSize` as independent query params instead of requiring both to be set before either was sent. Passing only `pageSize` without `page` previously had it silently dropped, so results came back at the server's default page size ([#6900](https://github.com/mem0ai/mem0/pull/6900))
|
||||
- **LLMs:** Add `providerOverride` to the Bedrock `LLMConfig`, an explicit provider name for when `model` is an application inference profile ARN whose opaque ID has no provider substring for `extractProvider()` to detect. Without it, those ARNs threw before the provider-specific settings could be initialized ([#6899](https://github.com/mem0ai/mem0/pull/6899))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Resolved 17 additional high and critical severity dependency vulnerabilities across 5 pnpm workspaces (`mem0-ts`, `vercel-ai-sdk`, `n8n-nodes-mem0`, `zapier-mem0`, `server/dashboard`) via `pnpm.overrides` and a `tar` patch ([#7032](https://github.com/mem0ai/mem0/pull/7032))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-11" description="v3.1.6">
|
||||
|
||||
**New Features:**
|
||||
- **Vector Stores:** Add an Oracle AI Vector Search vector store (`oracledb`) to the OSS SDK, with pooled connections, `HNSW`/`IVF` indexes, an optional `indexAccuracy` target, JSON payload filtering, and six selectable distance metrics ([#6690](https://github.com/mem0ai/mem0/pull/6690))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Core:** Percent-escape `%`, `&`, and `=` in `userId`, `agentId`, and `runId` when building the session scope key for the recent-conversation buffer, so the key stays unambiguous for ids containing those characters. Ordinary ids keep their existing key; an id already containing `%`, `&`, or `=` maps to a new key, so its buffer starts empty once and refills on the next `add()`. Stored memories are unaffected ([#6892](https://github.com/mem0ai/mem0/pull/6892))
|
||||
- **Vector Stores:** Close and clear the Oracle pool that Mem0 created when `initialize()` fails, and reset the cached init promise so the next call retries instead of replaying the rejection forever. A caller-supplied `client` is left untouched ([#6839](https://github.com/mem0ai/mem0/pull/6839))
|
||||
- **Vector Stores:** Validate Oracle `insert()` batches before touching the database: `ids` and `payloads` must match `vectors` in length, so a short array can no longer write rows with `undefined` ids or silently drop payloads ([#6839](https://github.com/mem0ai/mem0/pull/6839))
|
||||
|
||||
**Improvements:**
|
||||
- **Vector Stores:** Cut Oracle round trips. `insert()` now sends the whole batch through one `executeMany()` with explicit `bindDefs` instead of one `INSERT` per vector, `list()` reads the total from a `COUNT(*) OVER ()` window in the same statement instead of issuing a second count query, and an unfiltered `search()` adds the `VECTOR_INDEX_TRANSFORM` hint so the vector index is used ([#6835](https://github.com/mem0ai/mem0/pull/6835))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Patched 8 high and 18 medium severity dependency vulnerabilities across the pnpm workspace via `pnpm.overrides` (`undici`, `brace-expansion`, `ip-address`) ([#6847](https://github.com/mem0ai/mem0/pull/6847))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-05" description="v3.1.5">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add `agentCustomInstructions` to `PromptUpdatePayload`, `AddMemoryOptions`, and `ProjectResponse`. It sets a second extraction instruction set that applies only to agent-scoped memories: an add passing `agentId` without `userId` uses it, one passing both splits by attribution, and while it is unset `customInstructions` continues to apply to every memory ([#6809](https://github.com/mem0ai/mem0/pull/6809))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="v3.1.4">
|
||||
|
||||
**New Features:**
|
||||
- **Client:** Add `referenceDate` and `keywordSearch` to `SearchMemoryOptions`, keeping the TypeScript client's typed search options in sync with the Platform API ([#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Client:** Take the `/v1/ping/` identity/telemetry call off the request critical path. Every method previously did `if (this.telemetryId === "") await this.ping();`, blocking the first call on each client instance on a network round trip; the ping now resolves in the background through a shared, credentials-keyed promise cache (FIFO-capped at 50 entries), so concurrent clients on the same host/API key share one ping instead of issuing one each, and a failed ping is not cached so the process can retry ([#6788](https://github.com/mem0ai/mem0/pull/6788))
|
||||
- **Client:** `deleteUsers()` now issues its per-entity DELETE requests through the shared `fetch()`-based helper instead of the axios instance, which defaulted to `keepAlive: false`. Deleting every user, agent, app, and run now reuses pooled connections instead of paying a fresh TCP/TLS handshake per entity ([#6788](https://github.com/mem0ai/mem0/pull/6788))
|
||||
- **Memory (OSS):** Stop `add()` metadata from setting or overwriting a memory's identity scope. Metadata now runs through the same `stripIdentityKeys()` helper as `update()`, so `user_id`/`agent_id`/`run_id` (snake_case or camelCase) and `actor_id` passed in metadata can no longer place a memory into a scope the caller didn't request through `userId`/`agentId`/`runId`/`filters` ([#6377](https://github.com/mem0ai/mem0/pull/6377))
|
||||
- **Vector Stores:** Fix Redis `search()` and `list()` building an invalid, empty RediSearch filter expression when `filters` was an empty object or contained only null/undefined values. The shared `buildRedisFilterExpr()` helper now falls back to `"*"` (match all) instead of joining zero conditions into `""` ([#6014](https://github.com/mem0ai/mem0/pull/6014))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-01" description="v3.1.3">
|
||||
|
||||
**New Features:**
|
||||
@@ -1427,7 +1598,7 @@ The largest provider release for the TypeScript OSS SDK so far: 17 new vector st
|
||||
**Improvements:**
|
||||
- **Telemetry:** Sample OSS hot-path events at 10% to reduce PostHog event volume ([#4771](https://github.com/mem0ai/mem0/pull/4771))
|
||||
|
||||
See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to-v3) for upgrade instructions.
|
||||
See the [OSS v2 to v3 migration guide](https://docs.mem0.ai/migration/oss-v2-to-v3) for upgrade instructions.
|
||||
|
||||
</Update>
|
||||
|
||||
@@ -1748,6 +1919,44 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
|
||||
|
||||
<Tab title="CLI">
|
||||
|
||||
<Update label="2026-09-18" description="Python v0.2.13 / Node v0.2.14">
|
||||
|
||||
**Improvements:**
|
||||
- **Client:** Requests now carry the three surface-identity headers (`X-Mem0-Source`, `X-Application`, `X-Mem0-Client`) introduced in the Python and TypeScript SDKs, so the platform can attribute calls made through the CLI to the correct surface and version ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="Python v0.2.12 / Node v0.2.13">
|
||||
|
||||
**New Features:**
|
||||
- **`version`:** New `mem0 version` subcommand, alongside the existing `--version` flag, so scripts and agent harnesses can read the CLI version as a regular subcommand instead of a root-level flag (Python and Node [#6907](https://github.com/mem0ai/mem0/pull/6907))
|
||||
- **`add`:** New `--agent-custom-instructions` flag, threaded through to `agent_custom_instructions` on the `/v3/memories/add/` payload: a second extraction instruction set that applies only to agent-scoped memories, matching the SDKs' `agentCustomInstructions` / `agent_custom_instructions` support (Python and Node [#6910](https://github.com/mem0ai/mem0/pull/6910))
|
||||
|
||||
**Documentation:**
|
||||
- **`search --filter`:** The `--filter` help text and `docs/platform/cli.mdx` now spell out the JSON shape (`{"AND": [...]}` / `{"OR": [...]}`) with a concrete example instead of just calling it "an advanced filter expression," and a matching example command was added to both the CLI help text and the docs page (Python and Node [#6907](https://github.com/mem0ai/mem0/pull/6907))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="Python v0.2.11 / Node v0.2.12">
|
||||
|
||||
**New Features:**
|
||||
- **`add`:** New `--custom-instructions`, `--custom-categories`, `--structured-data-schema`, and `--timestamp` flags, matching the Platform `/v3/memories/add/` payload fields (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
- **`search`:** New `--show-expired`, `--reference-date`, and `--latest-only` flags, forwarded to `/v3/memories/search/` as `show_expired`, `reference_date`, and `latest_only` (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
- **`list`:** New `--show-expired` and `--latest-only` flags (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
- **`update`:** New `--expires` and `--timestamp` flags (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
- **`delete`:** New `--delete-linked` flag to also delete memories linked to the target memory (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
|
||||
**Bug Fixes:**
|
||||
- **`help --json`:** Emit JSON automatically under agent mode (`--agent`), not only when `--json` is passed explicitly. Python checks `is_agent_mode()` and now renders through `console.print_json()` instead of a plain `console.print(json.dumps(...))` call; Node also checks the root `--agent` flag in addition to the subcommand's `--json` flag (Python and Node [#6773](https://github.com/mem0ai/mem0/pull/6773))
|
||||
|
||||
**Changes:**
|
||||
- **`add`:** `--categories` is no longer forwarded on `add`. The `/v3/memories/add/` payload has no `categories` field (only `custom_categories`), so the CLI was sending a key the endpoint does not accept. Passing the flag now exits 1 with a message pointing to `--custom-categories` (Python and Node [#6696](https://github.com/mem0ai/mem0/pull/6696))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies (Node):** Tighten the `postcss` pnpm override from `<8.5.10 → >=8.5.10` to `<8.5.18 → >=8.5.18 <9.0.0`, closing a newer CVE range the previous floor didn't cover, as part of a wider dependency patch sweep across the pnpm workspaces ([#6639](https://github.com/mem0ai/mem0/pull/6639))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-13" description="Python v0.2.10 / Node v0.2.11">
|
||||
|
||||
**Bug Fixes:**
|
||||
@@ -1913,6 +2122,58 @@ A full-featured command-line interface for Mem0, available in both Python and No
|
||||
<Tabs>
|
||||
<Tab title="Mem0 Plugin">
|
||||
|
||||
<Update label="2026-09-08" description="Shared agent plugin runtime">
|
||||
|
||||
**Changed:**
|
||||
- Consolidated the coding-agent integrations into `integrations/agent-plugin-core/`: one Python runtime, one TypeScript utility library, and six canonical Python-plugin skill templates. Native adapters retain each host's event contracts and capabilities.
|
||||
- Python plugins ship generated, self-contained `core/` and `skills/` directories. Builds validate portable schemas and skills, parse native JSON, and reject generated-file drift, missing files, stale generated files, and symlinks. TypeScript packages bundle the shared source into their distributable JavaScript and verify their entry points.
|
||||
- Replaced the old `integrations/mem0-plugin/` layout with native host directories and one portable `integrations/mem0-agent-plugin/` package. Updated marketplace paths, installation guides, and integration-skill links. OpenCode now lives in `integrations/opencode-plugin/`.
|
||||
- Native Python plugins expose one local, read-only `search_memories` MCP tool and six skills: search, remember, forget, status, pause, and resume. The shared search tool accepts optional `run_id` with every scope (`repo`, `dir`, and `mine`) to recall memories from a specific coding-agent session. Omitting it searches across sessions. This local tool is separate from the hosted Mem0 MCP server's tool set.
|
||||
|
||||
**Fixes:**
|
||||
- Hooks, controls, MCP servers, and detached workers use the same host-specific data directory. Detached workers retain the host identity and telemetry source; `--plugin-data-dir` reaches the shared resolver.
|
||||
- Session-end workers flush the conversation already captured by hooks. Repeated and concurrent response hooks no longer duplicate an answer, while identical answers after separate prompts are preserved.
|
||||
- Shared prompts and responses are redacted without the previous 6,000-character cutoff. Python extraction splits oversized messages without dropping text to enforce each request's input budget. Flush event selection and claims share one write transaction, delayed handoffs are replaced atomically, and permanent HTTP polling errors fail promptly.
|
||||
- Extraction instructions refer to the current coding agent. Python redaction covers JSON-shaped credentials; both telemetry runtimes recursively remove sensitive keys, including keys inside nested lists.
|
||||
- New Git repository writes use a hash of the remote identity in `agent_id`. Search and explicit shared-memory deletion include both current and legacy repository IDs within the repository's `app_id`. Existing memories are not rewritten. Legacy IDs retain their original ambiguity for matching owner/repository names on different Git hosts.
|
||||
|
||||
**Packaging:**
|
||||
- Claude Code, Cursor, Codex, Kimi, Antigravity, and the portable Python bundle are versioned at `0.3.1`. OpenCode and DeepSeek Harness are `0.3.0`; Pi Agent is `0.3.0`; OpenClaw is `1.1.0`. Each host's changes and upgrade considerations are listed in its tab.
|
||||
- Python and TypeScript CI run their respective runtime suites. Package checks build the installable artifacts, check generated-file consistency, and reject TypeScript output that still imports monorepo source.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="mem0-plugin v0.2.15">
|
||||
|
||||
**Fixes:**
|
||||
- **Search:** A failed search request now prints `[mem0] search request failed: <error>` to stderr before returning no results. `search_memories()` swallowed every exception and returned `[]`, so an expired API key, a network failure, or a 500 from the backend was indistinguishable from a genuine "nothing stored yet" and the agent carried on with no context and no warning. Shared by Claude Code, Cursor, Codex, Antigravity, and Kimi ([#6898](https://github.com/mem0ai/mem0/pull/6898))
|
||||
- **Cursor:** `mcpServers` in `.cursor-plugin/plugin.json` now points at `./.cursor-mcp.json` instead of `.cursor-mcp.json`. The un-prefixed path resolved inconsistently depending on Cursor's working directory when it loaded the plugin ([#6948](https://github.com/mem0ai/mem0/pull/6948))
|
||||
- **Codex:** `install_codex_hooks.py` now prints all six registered events (`PreToolUse, SessionStart, UserPromptSubmit, PostToolUse, Stop, PreCompact`) after installing, instead of a stale four-event list left over from an earlier version of the installer. The README's hook table is corrected to match, documenting the three `PreToolUse` handlers and two `PostToolUse` handlers that were previously undocumented ([#6948](https://github.com/mem0ai/mem0/pull/6948))
|
||||
|
||||
**Documentation:**
|
||||
- New [Claude.ai](/integrations/claude-ai) integration page ([#6948](https://github.com/mem0ai/mem0/pull/6948))
|
||||
|
||||
<Note>
|
||||
The Claude Code, Cursor, and Codex per-editor manifests (`.claude-plugin/plugin.json`, `.cursor-plugin/plugin.json`, `.codex-plugin/plugin.json`) had drifted to `0.2.13` while the `.claude-plugin/marketplace.json` and `.cursor-plugin/marketplace.json` listings had already moved to `0.2.14`, so installs were pinned one release behind what the marketplace advertised. This release realigns every manifest and marketplace listing to `0.2.15`.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="mem0-plugin v0.2.14">
|
||||
|
||||
**Fixes:**
|
||||
- **Settings loading no longer crashes on a malformed `settings.json`:** If `~/.mem0/settings.json` parsed as valid JSON but wasn't an object (a list or a bare string, for example), `load_settings()` called `.items()` on it and raised. `resolve_config()` guards only against `ImportError`, so the failure escaped into every hook that resolves identity, not just setup. Settings loading now keeps the defaults instead. Setup also stopped claiming it "Created" the settings file when one already existed; it only prints that when it actually wrote one. Shared across Claude Code, Cursor, Codex, and Antigravity.
|
||||
|
||||
**New Features:**
|
||||
- **Unknown settings key warning:** Setup now flags keys in `settings.json` that the plugin doesn't recognize, so a typo'd setting no longer fails silently.
|
||||
|
||||
**Removed:**
|
||||
- Dropped the `mem0_doc_search` "openmemory" section now that OpenMemory has been removed from the docs site, so the skill no longer links to pages that don't exist.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-14" description="mem0-plugin v0.2.13">
|
||||
|
||||
**Fixes:**
|
||||
@@ -2170,8 +2431,163 @@ Initial release of the Mem0 plugin for Claude Code and Cursor, followed by Codex
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Claude Code">
|
||||
|
||||
<Update label="2026-09-23" description="Claude Code plugin v0.3.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer tells the agent to call it before answering anything that could depend on prior context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, which reduces unnecessary searches ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Sidekick:** Sidekick searches memories when earlier sessions could help, instead of before every answer ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Extraction:** Repository memory instructions are shorter. They no longer ask for a dedicated memory for each command that failed and was then fixed, and no longer carry separate rules against saving personal preferences or memories that only name the repository, branch, or directory ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Search skill:** `/search` no longer describes categories as best-effort labels or asks for a retry without the category ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Packaging:** `PLUGIN_VERSION` bumped to `0.3.3`, so the `mem0-plugin/<version>` wire header and `plugin_version` telemetry field identify builds with these prompts ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Claude Code plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** `PLUGIN_VERSION` bumped to `0.3.2`. The `mem0-plugin/<version>` wire header and `plugin_version` telemetry field now reflect the fixes from #7322 through #7358 ([#7373](https://github.com/mem0ai/mem0/pull/7373))
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
**Changes:**
|
||||
- **Sidekick:** Sidekick is now available only in Claude Code, with Sonnet, worktree isolation, and parent memories.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Claude Code plugin v0.3.1">
|
||||
|
||||
**Changed:**
|
||||
- Extracted hook orchestration and memory behavior into the shared Python core; Claude transcript parsing remains in its native adapter. The installed package contains the generated runtime rather than importing files outside its plugin directory.
|
||||
- Preserves the public `mem0` name, hook declarations, MCP launch configuration, user configuration, and `mem0:sidekick` worktree behavior. The manifest and marketplace version advance from `0.3.0` to `0.3.1` so installations can identify the update.
|
||||
|
||||
**Fixes:**
|
||||
- Session-end extraction no longer appends a final answer already captured from the transcript while an earlier extraction was running.
|
||||
- Existing repository memories remain searchable after the shared-ID change; explicit shared-memory deletion also covers the legacy ID. Background workers and control skills consistently use Claude's data directory.
|
||||
- Receives the shared JSON-secret redaction and nested telemetry filtering fixes. The local search tool exposes query, result count, category, scope, and optional `run_id` for session-specific recall across all scopes.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Cursor">
|
||||
|
||||
<Update label="2026-09-23" description="Cursor plugin v0.3.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer tells the agent to call it before answering anything that could depend on prior context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, which reduces unnecessary searches ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Extraction:** Repository memory instructions are shorter. They no longer ask for a dedicated memory for each command that failed and was then fixed, and no longer carry separate rules against saving personal preferences or memories that only name the repository, branch, or directory ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Search skill:** `/search` no longer describes categories as best-effort labels or asks for a retry without the category ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Packaging:** `PLUGIN_VERSION` bumped to `0.3.3`, so the `mem0-plugin/<version>` wire header and `plugin_version` telemetry field identify builds with these prompts ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Cursor plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** `PLUGIN_VERSION` bumped to `0.3.2`. The `mem0-plugin/<version>` wire header and `plugin_version` telemetry field now reflect the fixes from #7322 through #7358 ([#7373](https://github.com/mem0ai/mem0/pull/7373))
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
**Changes:**
|
||||
- **Sidekick:** Removes Sidekick and its start/stop hooks. Memory capture, search, and six skills remain available.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Cursor plugin v0.3.1">
|
||||
|
||||
**Changed:**
|
||||
- Moves from the legacy shared editor-plugin directory to a native `integrations/cursor-plugin/` package with generated Python core and skills, Cursor variables, local MCP configuration, and a native Sidekick.
|
||||
- Translates Cursor conversation/workspace fields, response and summary fields, tool outcomes, and subagent lifecycle events into the shared runtime. The Sidekick searches memory itself because Cursor's subagent-start response cannot inject parent context.
|
||||
|
||||
**Fixes:**
|
||||
- Adapter errors are logged and exit successfully so a memory failure does not terminate the host hook. Sidekick telemetry reports zero parent-injected context because this host uses self-search.
|
||||
- Repeated response events and Stop/session-end capture do not duplicate the same answer.
|
||||
- Receives shared data-directory handling, background-worker identity, redaction, and legacy-memory retrieval fixes.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Codex">
|
||||
|
||||
<Update label="2026-09-23" description="Codex plugin v0.3.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer tells the agent to call it before answering anything that could depend on prior context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, which reduces unnecessary searches ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Extraction:** Repository memory instructions are shorter. They no longer ask for a dedicated memory for each command that failed and was then fixed, and no longer carry separate rules against saving personal preferences or memories that only name the repository, branch, or directory ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Search skill:** `/search` no longer describes categories as best-effort labels or asks for a retry without the category ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Packaging:** `PLUGIN_VERSION` bumped to `0.3.3`, so the `mem0-plugin/<version>` wire header and `plugin_version` telemetry field identify builds with these prompts ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Codex plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** `PLUGIN_VERSION` bumped to `0.3.2`. The `mem0-plugin/<version>` wire header and `plugin_version` telemetry field now reflect the fixes from #7322 through #7358 ([#7373](https://github.com/mem0ai/mem0/pull/7373))
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
**Changes:**
|
||||
- **Sidekick:** Renames shared tracking to use subagent terminology. Native subagent memory support remains available.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Codex plugin v0.3.1">
|
||||
|
||||
**Changed:**
|
||||
- Moves from the legacy shared editor-plugin directory to a native `integrations/codex-plugin/` package, with generated Python core and six skills, a local search MCP server, and native lifecycle hooks.
|
||||
- Resolves MCP repository searches from Codex workspace metadata when supplied. Control skills, hooks, and workers use the same plugin data directory.
|
||||
- Native subagent start/stop hooks supply parent-retrieved memory context and record completions for every native subagent. Named custom agents remain project/user configuration; the plugin does not distribute a named Codex Sidekick.
|
||||
|
||||
**Fixes:**
|
||||
- Receives shared credential redaction, legacy-memory retrieval, background-worker identity, and duplicate-response fixes. Codex tool outcomes use available structured failure indicators; missing outcome information is recorded as unknown.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="OpenCode">
|
||||
|
||||
<Update label="2026-09-23" description="OpenCode plugin v0.4.1">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer asks the agent to search proactively or to run several searches for multi-part questions. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, the same wording as the other coding-agent plugins ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Session context:** Removed two system-context lines that told the agent to run 2 parallel searches before responding and 2-4 parallel searches for non-trivial tasks ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Skills:** `/mem0-search` and `/mem0-context-loader` make one `search_memories` call instead of 2 and 2-4 parallel calls. `/mem0-context-loader` now uses the search skill description from the other coding-agent plugins instead of asking to load at every new task or context switch ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="OpenCode plugin v0.4.0">
|
||||
|
||||
**Changes:**
|
||||
- **Telemetry:** The PostHog `source` tag changed from the literal `"plugin"` to `OPENCODE_PLUGIN`, and `project_hash` is now salted. Saved PostHog insights filtering on `source = "plugin"` will stop matching new events; historical data is unaffected ([#7322](https://github.com/mem0ai/mem0/pull/7322))
|
||||
- **Config:** A new `keyFingerprint` key appears in the install-count deduplication logic; installs are now counted once per key rather than on every activation ([#7325](https://github.com/mem0ai/mem0/pull/7325))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="OpenCode plugin v0.3.0">
|
||||
|
||||
**Changed:**
|
||||
- Moved the source from `integrations/mem0-plugin/.opencode-plugin/` to `integrations/opencode-plugin/`, retaining the `@mem0/opencode-plugin` package name and native OpenCode hooks.
|
||||
- Reuses shared conversation preparation, redaction, scoping, and telemetry. Builds a self-contained Bun/ESM `dist/index.js` and publishes its TypeScript entry declaration.
|
||||
- Global memory tool scope requires the user to enable it in plugin settings first; empty and wildcard identities are rejected.
|
||||
- Retains the seven commands for context loading, search, remember, forget, scope, status, and tour; bundled skills continue loading through OpenCode's native configuration.
|
||||
|
||||
**Removed:**
|
||||
- Removed auto-Dream consolidation, its gates and state handling, and the Dream and pin skills/commands. Existing configurations and workflows that use these features must be updated.
|
||||
|
||||
**Builds:**
|
||||
- Updated build and publish paths for the relocated source directory; the existing release tag prefix and publishing workflow filename are unchanged.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-22" description="OpenCode plugin v0.2.2">
|
||||
|
||||
**Fixes:**
|
||||
@@ -2252,6 +2668,63 @@ Initial release of the Mem0 plugin for Claude Code and Cursor, followed by Codex
|
||||
|
||||
<Tab title="Antigravity">
|
||||
|
||||
<Update label="2026-09-23" description="Antigravity plugin v0.3.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer tells the agent to call it before answering anything that could depend on prior context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, which reduces unnecessary searches ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Extraction:** Repository memory instructions are shorter. They no longer ask for a dedicated memory for each command that failed and was then fixed, and no longer carry separate rules against saving personal preferences or memories that only name the repository, branch, or directory ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Search skill:** `/search` no longer describes categories as best-effort labels or asks for a retry without the category ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Packaging:** `PLUGIN_VERSION` bumped to `0.3.3`, so the `mem0-plugin/<version>` wire header and `plugin_version` telemetry field identify builds with these prompts ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Antigravity plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** `PLUGIN_VERSION` bumped to `0.3.2`. The `mem0-plugin/<version>` wire header and `plugin_version` telemetry field now reflect the fixes from #7322 through #7358 ([#7373](https://github.com/mem0ai/mem0/pull/7373))
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
**Changes:**
|
||||
- **Sidekick:** Removes Sidekick. Memory capture, search, and six skills remain available.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Antigravity plugin v0.3.1">
|
||||
|
||||
**Changed:**
|
||||
- Ships a native package with generated Python core and six skills, a local search MCP server, a Sidekick declaration, and an adapter for `PreInvocation`, `PostToolUse`, and `Stop`.
|
||||
- Normalizes conversation IDs, transcript paths, workspace paths, tool calls, and errors. The adapter captures all completed user/assistant transcript messages incrementally, including later-turn intent, without replaying earlier messages.
|
||||
- Sidekick searches Mem0 itself; this plugin does not provide Claude Code's worktree isolation.
|
||||
|
||||
**Fixes and host limitations:**
|
||||
- Accepts `MEM0_CWD` as an explicit workspace fallback when the host omits `workspacePaths`. Skips capture when neither is available, rather than writing under an unrelated directory.
|
||||
- Documents global MCP registration with `agy mcp add` when the host does not register the plugin-scoped server. Recall on the initial invocation depends on the host providing a prompt or readable transcript.
|
||||
- Receives the shared data-directory, redaction, legacy-memory retrieval, and duplicate-response fixes.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="Antigravity plugin v0.1.7">
|
||||
|
||||
**Fixes:**
|
||||
- **Hooks:** The `mem0-ensure-deps` and `mem0-session-start` hook commands in `hooks.json` no longer redirect stderr to `/dev/null`. Both commands still end in `|| true` so a failure can't block startup, but a broken dependency install or session bootstrap now shows up in the Antigravity hook log instead of failing invisibly ([#6948](https://github.com/mem0ai/mem0/pull/6948))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="Antigravity plugin v0.1.6">
|
||||
|
||||
**Fixes:**
|
||||
- **Settings loading no longer crashes on a malformed `settings.json`:** If `~/.mem0/settings.json` parsed as valid JSON but wasn't an object, every hook that resolves identity previously raised, not just setup. It now keeps the defaults instead, and setup only reports it "Created" the settings file when it actually wrote one.
|
||||
|
||||
**Improvements:**
|
||||
- **Unknown settings key warning:** Setup now flags keys in `settings.json` it doesn't recognize instead of ignoring them silently.
|
||||
|
||||
**Removed:**
|
||||
- Dropped the doc-search skill's "openmemory" section now that OpenMemory has been removed from the docs site.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-14" description="Antigravity plugin v0.1.5">
|
||||
|
||||
**Fixes:**
|
||||
@@ -2306,8 +2779,103 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Kimi">
|
||||
|
||||
<Update label="2026-09-23" description="Kimi Code plugin v0.3.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memories` tool description no longer tells the agent to call it before answering anything that could depend on prior context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help, which reduces unnecessary searches ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Extraction:** Repository memory instructions are shorter. They no longer ask for a dedicated memory for each command that failed and was then fixed, and no longer carry separate rules against saving personal preferences or memories that only name the repository, branch, or directory ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Search skill:** `/search` no longer describes categories as best-effort labels or asks for a retry without the category ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Packaging:** `PLUGIN_VERSION` bumped to `0.3.3`, so the `mem0-plugin/<version>` wire header and `plugin_version` telemetry field identify builds with these prompts ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Kimi Code plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** `PLUGIN_VERSION` bumped to `0.3.2`. The `mem0-plugin/<version>` wire header and `plugin_version` telemetry field now reflect the fixes from #7322 through #7358 ([#7373](https://github.com/mem0ai/mem0/pull/7373))
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
**Changes:**
|
||||
- **Sidekick:** Removes Sidekick and its start/stop hooks. Memory capture, recall, and six skills remain available.
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Kimi Code plugin v0.3.1">
|
||||
|
||||
**Changed:**
|
||||
- Ships a self-contained native package with six skills, nine lifecycle hooks, a local search MCP server, and a native Sidekick declaration. Added a dedicated installation and troubleshooting guide.
|
||||
- Translates Kimi's session, prompt, tool, compaction, shutdown, and subagent events into the shared Python runtime. Sidekicks receive parent memory context through Kimi's native lifecycle.
|
||||
|
||||
**Fixes:**
|
||||
- Recovers completed assistant output from Kimi's indexed v2 wire transcript when Stop events omit the response text. Repeated Sidekick invocations receive distinct run identifiers. Stops without a host ID are left uncorrelated when multiple matching runs are active, preserving their responses without assigning them to the wrong run.
|
||||
- Keeps controls, hooks, MCP, and detached workers on the same Kimi data directory and preserves host identity in background workers.
|
||||
- Receives the shared redaction, legacy-memory retrieval, and duplicate-response fixes.
|
||||
|
||||
**Host compatibility:**
|
||||
- Documents `CHOKIDAR_USEPOLLING=1` for the observed macOS watcher issue. Filesystem isolation remains Kimi's responsibility.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="kimi-plugin v0.1.0">
|
||||
|
||||
**Initial release** of the Mem0 plugin for Kimi Code, sharing its scripts, skills, and marketplace listing with the Claude Code / Cursor / Codex / Antigravity plugin family ([#6919](https://github.com/mem0ai/mem0/pull/6919))
|
||||
|
||||
**New Features:**
|
||||
- **MCP server:** Registers the hosted Mem0 MCP server at `https://mcp.mem0.ai/mcp/`, authenticated via the `MEM0_API_KEY` env var as a bearer token.
|
||||
- **Lifecycle hooks:** Wires SessionStart (loads context through the `context-loader` skill), UserPromptSubmit, three PreToolUse hooks (blocks direct `Write`/`Edit`/`MultiEdit` to memory files, enforces metadata defaults on Mem0 MCP tool calls, and injects context on file reads), two PostToolUse hooks (post-tool tracking and Bash-output scanning), Stop, and PreCompact.
|
||||
- **Hook adapter:** `kimi_hook_shim.sh` normalizes Kimi Code's hook contract to what the shared hook scripts expect: it resolves the real project directory from the payload's `cwd` (Kimi forces the plugin root as the working directory), converts the array-shaped `prompt` field and the `tool_output` / `tool_input.path` field names to the Claude-style shapes the scripts already handle, and translates the plugin-scoped MCP tool name prefix.
|
||||
- **Shared policy skill:** Bundles the `/mem0:policy` skill for managing the `## Instructions` and `## Agent Instructions` sections of `mem0.md`.
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="OpenClaw">
|
||||
|
||||
<Update label="2026-09-23" description="openclaw-mem0 v1.2.1">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `memory_search` tool description no longer asks the agent to search proactively or to run several searches for multi-part questions. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help. Recall strategies (`smart`, `always`, `manual`) are unchanged ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="openclaw-mem0 v1.2.0">
|
||||
|
||||
**Changes:**
|
||||
- **Config:** Added `keyFingerprint` to the config schema for install-count deduplication; installs are now counted once per key rather than on every activation ([#7325](https://github.com/mem0ai/mem0/pull/7325))
|
||||
- **Telemetry:** Events are no longer delivered twice, and the `plugin_version` field now reflects the plugin that produced the event ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="openclaw-mem0 v1.1.0">
|
||||
|
||||
**Changed:**
|
||||
- Reuses shared conversation preparation, redaction, and telemetry while retaining OpenClaw's native memory backend, tools, CLI, and Platform/OSS modes.
|
||||
- Continues to publish a self-contained ESM package under `@mem0/openclaw-mem0`; the plugin manifest and package version now agree.
|
||||
|
||||
**Removed:**
|
||||
- Removed Dream consolidation: automatic scheduling and locking, `openclaw mem0 dream`, Dream configuration, the memory-dream skill, and Dream-state public artifacts. Triage, recall, and memory/entity artifacts remain available. Update configurations or integrations that use the removed Dream surface.
|
||||
|
||||
**Fixes:**
|
||||
- `openclaw mem0 status` handles an unconfigured installation without crashing and directs users to setup.
|
||||
- Removed OpenClaw's separate 2,000-character extraction cutoff. Selected user and assistant messages retain their full redacted text; recent-message selection, earlier summary selection, and noise filtering still apply.
|
||||
- Telemetry removes sensitive properties recursively and uses the shared failure-safe delivery implementation.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="openclaw-mem0 v1.0.16">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Tightened the `undici` pnpm override from `<6.27.0 → >=6.27.0 <8.0.0` to `<7.29.0 → >=7.29.0 <8.0.0`, closing a newer CVE range the previous floor didn't cover, as part of a wider dependency patch sweep across the pnpm workspaces ([#6847](https://github.com/mem0ai/mem0/pull/6847))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-01" description="openclaw-mem0 v1.0.15">
|
||||
|
||||
**Improvements:**
|
||||
@@ -2571,6 +3139,47 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="Pi Agent">
|
||||
|
||||
<Update label="2026-09-23" description="Pi Agent plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The memory policy, `mem0_memory` tool description, and prompt guidelines no longer ask the agent to search before answering anything that may depend on earlier context or to run several searches per question. They now ask for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Skills:** `context-loader` makes one search instead of 2-4 parallel searches, and uses the search skill description from the other coding-agent plugins ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Automatic recall:** Injected memories are introduced as "Mem0 found these relevant memories from earlier work in this repository:", the same heading as the Python plugins. The old heading called them a shallow first pass and told the agent to search again ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="Pi Agent plugin v0.3.1">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** Events are no longer delivered twice, no longer lose parked events, and now attribute each event to the plugin that produced it. The `plugin_version` wire field reflects the fixed release ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="Pi Agent plugin v0.3.0">
|
||||
|
||||
**Changed:**
|
||||
- Reuses shared conversation preparation, memory formatting, project/session/global scope utilities, and telemetry while preserving Pi's native extension API and `@mem0/pi-agent-plugin` package name.
|
||||
- Pi loads the built `dist/entry.js` extension instead of executing source TypeScript from an installed package. Builds also publish the library entry point and declarations.
|
||||
|
||||
**Removed:**
|
||||
- Removed Dream consolidation and pin commands, skills, configuration, types, and exports. The remaining commands are remember, search, forget, tour, scope, and status. Update integrations that import removed APIs or invoke removed commands.
|
||||
|
||||
**Fixes:**
|
||||
- Global memory tool scope requires the user to select `/mem0-scope global` or configure a global default first. Empty and wildcard identities are rejected.
|
||||
- Memory update and delete accept the `mem0:<uuid>` and `[mem0:<uuid>]` citations displayed in tool results, as well as raw IDs.
|
||||
- Shared capture preparation filters conversation roles and redacts content; telemetry removes sensitive keys inside nested structures.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="Pi Agent plugin v0.1.5">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Tightened the `undici` pnpm override from `<6.27.0 → >=6.27.0 <8.0.0` / `>=8.0.0 <8.5.0 → >=8.5.0` to `<7.29.0 → >=7.29.0 <8.0.0` / `>=8.0.0 <8.9.0 → >=8.9.0 <9.0.0`, closing a newer CVE range the previous floors didn't cover, as part of a wider dependency patch sweep across the pnpm workspaces ([#6847](https://github.com/mem0ai/mem0/pull/6847))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-01" description="Pi Agent plugin v0.1.4">
|
||||
|
||||
**Security:**
|
||||
@@ -2628,8 +3237,110 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Strands">
|
||||
|
||||
<Update label="2026-08-25" description="mem0-strands v0.1.1">
|
||||
|
||||
**New Features:**
|
||||
- **Usage telemetry:** Anonymous usage events (`strands.store.init`, `strands.store.search`, `strands.store.add`, `strands.store.add_messages`) ride the Mem0 SDK's existing PostHog client, unsampled, with no new dependency. Events carry only counts, durations, booleans, and coarse failure kinds: never queries, memory text, message content, entity ids, metadata, or API keys. Opt out with `MEM0_TELEMETRY=false` ([#7110](https://github.com/mem0ai/mem0/pull/7110))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="mem0-strands v0.1.0">
|
||||
|
||||
**Initial release** of [`mem0-strands`](https://pypi.org/project/mem0-strands/), a native `MemoryStore` that plugs Mem0 into the [Strands Agents](https://strandsagents.com/) `MemoryManager` ([#7021](https://github.com/mem0ai/mem0/pull/7021))
|
||||
|
||||
**New Features:**
|
||||
- **Automatic recall and injection:** `Mem0MemoryStore.search()` runs every turn through the `MemoryManager`, so relevant memories are searched and prepended to the prompt with no explicit tool call required.
|
||||
- **Server-side extraction:** `add_messages()` renders raw conversation turns to text and hands them to Mem0's own extraction pipeline (`infer=True`), so enabling extraction skips an extra client-side model call to distill facts first.
|
||||
- **Verbatim writes:** `add()` stores a single fact exactly as given (`infer=False`), the sink used by the `add_memory` tool or a client-side extractor.
|
||||
- **Entity scoping:** Accepts `user_id`, `agent_id`, `run_id`, and `app_id`; at least one is required, and mixing the platform-only `app_id` with a self-hosted `config` raises at construction instead of failing on the first write.
|
||||
- **Hosted or self-hosted:** Defaults to the hosted Mem0 Platform via `api_key` (or `$MEM0_API_KEY`), or pass a `config` dict for a self-hosted Mem0 OSS backend.
|
||||
- **Non-blocking construction:** The underlying Mem0 client is built lazily on first use inside `asyncio.to_thread`, so API-key validation and OSS embedder/vector-store setup never block the event loop.
|
||||
|
||||
<Note>
|
||||
`Mem0MemoryStore` is the automatic-recall store for the `MemoryManager`. For a model-called tool instead, use the [`mem0_memory`](https://github.com/strands-agents/tools) tool from `strands-agents-tools`; both share the same Mem0 backend and namespace. See [Strands Agents](/integrations/strands) for setup.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="DeepSeek Harness">
|
||||
|
||||
<Update label="2026-09-23" description="deepseek-plugin v0.3.2">
|
||||
|
||||
**Improvements:**
|
||||
- **Search:** The `search_memory` tool description no longer asks the agent to search proactively before answering anything that may depend on earlier context. It now asks for a search before repeating investigation or when earlier decisions, fixes, commands, or results may help ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
- **Automatic recall:** Injected memories are introduced as "Mem0 found these relevant memories from earlier work:". The old heading called them a shallow first pass and told the agent to search again with `mem0_memory`, a tool DeepSeek does not have ([#7420](https://github.com/mem0ai/mem0/pull/7420))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-18" description="deepseek-plugin v0.3.1">
|
||||
|
||||
**Improvements:**
|
||||
- **Telemetry:** Rebuild with the fixed shared telemetry core from `agent-plugin-core`. Events are no longer delivered twice, no longer lose parked events on flush, and now attribute each event to the plugin that produced it ([#7323](https://github.com/mem0ai/mem0/pull/7323), [#7324](https://github.com/mem0ai/mem0/pull/7324), [#7358](https://github.com/mem0ai/mem0/pull/7358))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-09-08" description="deepseek-plugin v0.3.0">
|
||||
|
||||
**Added:**
|
||||
- Automatic recall during `system-prompt/assemble`, using the latest human prompt and avoiding repeated context injection within a session.
|
||||
- Automatic capture from the durable `session/event` stream after a completed turn. Interrupted or incomplete turns are not sent through this automatic capture path. `autoRecall` and `autoCapture` default to `true` and can be disabled.
|
||||
|
||||
**Changed:**
|
||||
- Reuses shared lifecycle, redaction, identity, and telemetry utilities while retaining the explicit `search_memory` and `add_memory` tools and their per-call agent/session scope. Cross-user `userId` overrides now require operator opt-in with `allowUserOverride: true`.
|
||||
- Publishes a self-contained ESM artifact under `@mem0/deepseek-plugin`; native Harness services and the Mem0 SDK remain external dependencies. Plugin cleanup remains tied to the native Cordis lifecycle.
|
||||
|
||||
**Host compatibility:**
|
||||
- Supports the declared Harness runtime dependencies and documents the macOS watcher workaround. The plugin does not bundle a named Sidekick or provide child filesystem isolation.
|
||||
|
||||
[#7203](https://github.com/mem0ai/mem0/pull/7203)
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-25" description="deepseek-plugin v0.1.1">
|
||||
|
||||
**New Features:**
|
||||
- **Usage telemetry:** Anonymous usage events (`deepseek.plugin.mounted`, `deepseek.tool.search_memory`, `deepseek.tool.add_memory`) are batched to PostHog over native fetch and flushed in the background. Events carry only tool names, durations, counts, and coarse failure kinds: never queries, memory text, filters, or API keys. Opt out with `MEM0_TELEMETRY=false` ([#7110](https://github.com/mem0ai/mem0/pull/7110))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="deepseek-plugin v0.1.0">
|
||||
|
||||
**Initial release** of [`deepseek-plugin`](https://www.npmjs.com/package/@mem0/deepseek-plugin), a native DeepSeek Harness (Cordis) plugin that registers Mem0 as two agent-callable tools ([#7027](https://github.com/mem0ai/mem0/pull/7027))
|
||||
|
||||
**New Features:**
|
||||
- **`search_memory`:** Recalls facts relevant to a query, with an optional `limit` (default 10) and per-call `userId` / `agentId` / `runId` scope overrides.
|
||||
- **`add_memory`:** Stores a fact for future sessions, tagged `source: "DEEPSEEK_HARNESS"` for backend attribution; extraction runs asynchronously server-side, so a stored fact may take a moment to become searchable.
|
||||
- **Cordis lifecycle:** `apply(ctx, config)` declares `inject = ['tools']`, so the plugin waits for the harness tool registry to exist, and both tools are registered via `ctx.tools.register()` so they auto-unregister when the plugin unmounts.
|
||||
- **Config:** `userId` is required; `apiKey` defaults to `$MEM0_API_KEY`; `host` optionally points at a dedicated Mem0 Platform base URL (not a switch to self-hosted Mem0 OSS).
|
||||
|
||||
<Note>
|
||||
Developer preview: auto-capture and auto-recall (memory injected into context automatically, without an explicit tool call) are planned but not yet built. The backend's `KNOWN_EVENT_SOURCES` allowlist also needs `"DEEPSEEK_HARNESS"` added before usage surfaces by name in telemetry rather than bucketing into "OTHERS". See [DeepSeek Harness](/integrations/deepseek-plugin) for setup.
|
||||
</Note>
|
||||
|
||||
</Update>
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab title="Vercel AI SDK">
|
||||
|
||||
<Update label="2026-09-18" description="Vercel AI SDK v3.0.3">
|
||||
|
||||
**Improvements:**
|
||||
- **Client:** Inherits the three surface-identity headers (`X-Mem0-Source`, `X-Application`, `X-Mem0-Client`) from the TypeScript SDK bump, so platform calls made through the Vercel AI SDK provider are now correctly attributed ([#7326](https://github.com/mem0ai/mem0/pull/7326))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-24" description="Vercel AI SDK v3.0.2">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Tightened the `js-yaml` pnpm overrides from `<3.15.0 → >=3.15.0 <4.0.0` / `>=4.0.0 <4.3.0 → >=4.3.0 <5.0.0` to `<3.15.1 → >=3.15.1 <4.0.0` / `>=4.0.0 <4.3.1 → >=4.3.1 <5.0.0`, closing a newer CVE range the previous floors didn't cover, as part of a wider dependency patch sweep across the pnpm workspaces ([#7032](https://github.com/mem0ai/mem0/pull/7032))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-01" description="Vercel AI SDK v3.0.1">
|
||||
|
||||
**Security:**
|
||||
@@ -2722,6 +3433,28 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="n8n">
|
||||
|
||||
<Update label="2026-08-24" description="n8n-nodes-mem0 v0.1.4">
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Add `js-yaml` pnpm overrides (`<3.15.1 → >=3.15.1 <4.0.0`, `>=4.0.0 <4.3.1 → >=4.3.1 <5.0.0`) to close a HIGH/CRITICAL severity advisory, as part of a wider dependency patch sweep across the pnpm workspaces ([#7032](https://github.com/mem0ai/mem0/pull/7032))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-05" description="n8n-nodes-mem0 v0.1.3">
|
||||
|
||||
**Changes:**
|
||||
- **License changed to MIT:** The published `@mem0/n8n-nodes-mem0` package is now MIT (was Apache-2.0). n8n's Creator Portal requires verified community nodes to be MIT, and the failing license check was the blocker for verification. The rest of the mem0 repo stays Apache-2.0 ([#6804](https://github.com/mem0ai/mem0/pull/6804))
|
||||
- **Themed icons:** The node and credential icons now declare `{ light, dark }` variants instead of a single icon, clearing the remaining `icon-prefer-themed-variants` warnings from the Creator Portal scan. No functional changes ([#6804](https://github.com/mem0ai/mem0/pull/6804))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="n8n-nodes-mem0 v0.1.2">
|
||||
|
||||
**Changes:**
|
||||
- **Package contact:** `author.email` in the published package is now `integrations@mem0.ai` (was `founders@mem0.ai`), so npm and n8n Creator Portal correspondence reaches the integrations team directly. No functional changes ([#6791](https://github.com/mem0ai/mem0/pull/6791))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-30" description="n8n-nodes-mem0 v0.1.1">
|
||||
|
||||
**Changes:**
|
||||
@@ -2751,6 +3484,29 @@ Existing memories written by the previous versions are not rewritten. If your me
|
||||
|
||||
<Tab title="Zapier">
|
||||
|
||||
<Update label="2026-08-24" description="Zapier app v0.1.2">
|
||||
|
||||
**Changes:**
|
||||
- **Connection label:** The saved connection now shows the account's email (`{{user_email}}`, read from the `/v1/ping/` test response) in the Zap editor instead of a static "Mem0" label, so a user with more than one Mem0 connection can tell them apart ([#6985](https://github.com/mem0ai/mem0/pull/6985))
|
||||
- **Action and search copy:** Reworded labels and descriptions to address Zapier's publishing review: **Get Memories** is now **Find Memories by User**, **Search Memories** is now **Find Memories**, and every description now reads as a third-person statement of what the step does ([#6985](https://github.com/mem0ai/mem0/pull/6985))
|
||||
- **Attribution:** Add Memory now tags writes with `source: "ZAPIER"` in the request body, so usage is attributed to this integration server-side ([#6985](https://github.com/mem0ai/mem0/pull/6985))
|
||||
|
||||
**Removed:**
|
||||
- **Client-side telemetry:** Deleted the embedded PostHog telemetry client (`telemetry.ts`) and its call sites in Add Memory, Get Memories, and Search Memories. Usage attribution now happens server-side via the `source: "ZAPIER"` tag above instead of a separate fire-and-forget analytics call from inside the published app ([#6985](https://github.com/mem0ai/mem0/pull/6985))
|
||||
|
||||
**Security:**
|
||||
- **Dependencies:** Tightened the `undici` pnpm override to `<7.29.0 → >=7.29.0 <8.0.0` / `>=8.0.0 <8.9.0 → >=8.9.0 <9.0.0` and added a `brace-expansion` override ([#6847](https://github.com/mem0ai/mem0/pull/6847)), then added a `js-yaml` override (`<3.15.1 → >=3.15.1 <4.0.0`, `>=4.0.0 <4.3.1 → >=4.3.1 <5.0.0`) closing a further HIGH/CRITICAL severity advisory ([#7032](https://github.com/mem0ai/mem0/pull/7032))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-08-04" description="Zapier app v0.1.1">
|
||||
|
||||
**Bug Fixes:**
|
||||
- **Add Memory:** **User ID** is now a required field. Mem0 rejects a write that carries no entity ID, so a Zap left blank failed at the API instead of in the editor. If you scoped memories only by Agent ID or Run ID, set a User ID as well ([#6790](https://github.com/mem0ai/mem0/pull/6790))
|
||||
- **Deployment:** Add a root `index.js` that re-exports the compiled app from `dist/`, and point `main` at it. Zapier's Lambda wrapper loads `<root>/index.js` and ignores the `package.json` `main` field, so the deployed app could not resolve its entry point ([#6789](https://github.com/mem0ai/mem0/pull/6789))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-07-29" description="Zapier app v0.1.0">
|
||||
|
||||
**Initial release** of the Mem0 Zapier app, built on the Zapier Platform CLI ([#6518](https://github.com/mem0ai/mem0/pull/6518))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Configurations
|
||||
title: "Embedder Configuration Reference"
|
||||
sidebarTitle: "Configurations"
|
||||
description: "Reference for embedder configuration options in Mem0, including provider selection and model settings."
|
||||
---
|
||||
|
||||
@@ -97,4 +98,4 @@ Here's a comprehensive list of all parameters that can be used across different
|
||||
|
||||
## Supported Embedding Models
|
||||
|
||||
For detailed information on configuring specific embedders, please visit the [Embedding Models](./models) section. There you'll find information for each supported embedder with provider-specific usage examples and configuration details.
|
||||
For detailed information on configuring specific embedders, please visit the [Embedding Models](./overview) section. There you'll find information for each supported embedder with provider-specific usage examples and configuration details.
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: AWS Bedrock
|
||||
title: "AWS Bedrock as Embedding Provider"
|
||||
sidebarTitle: "AWS Bedrock"
|
||||
description: "Configure AWS Bedrock as an embedding provider in Mem0 with IAM credentials and boto3 authentication."
|
||||
---
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Azure OpenAI
|
||||
title: "Azure OpenAI as Embedding Provider"
|
||||
sidebarTitle: "Azure OpenAI"
|
||||
description: "Configure Azure OpenAI as an embedding provider in Mem0 with API key, deployment, and endpoint settings."
|
||||
---
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Google AI
|
||||
title: "Google AI as Embedding Provider"
|
||||
sidebarTitle: "Google AI"
|
||||
description: "Configure Google AI as an embedding provider in Mem0 using Gemini models and the GOOGLE_API_KEY variable."
|
||||
---
|
||||
|
||||
@@ -99,6 +99,7 @@ Here are the parameters available for configuring the Hugging Face embedder:
|
||||
| `embedding_dims` | Dimensions of the embedding model | `selected_model_dimensions` |
|
||||
| `model_kwargs` | Additional arguments for the model | `None` |
|
||||
| `huggingface_base_url` | URL to connect to Text Embeddings Inference (TEI) API | `None` |
|
||||
| `api_key` | API key for the endpoint; falls back to the `HUGGINGFACE_API_KEY` env var. Only used on the `huggingface_base_url` path | `"hf"` |
|
||||
</Tab>
|
||||
<Tab title="TypeScript">
|
||||
| Parameter | Description | Default Value |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: LangChain
|
||||
title: "LangChain as Embedding Provider"
|
||||
sidebarTitle: "LangChain"
|
||||
description: "Use LangChain as an embedding provider in Mem0 to access a wide range of models through a unified interface."
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "LM Studio"
|
||||
title: "LM Studio as Embedding Provider"
|
||||
sidebarTitle: "LM Studio"
|
||||
description: "Configure LM Studio as an embedding provider in Mem0 for local embedding generation with models like nomic-embed-text."
|
||||
---
|
||||
You can use embedding models from LM Studio to run Mem0 locally.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: "Ollama"
|
||||
title: "Ollama as Embedding Provider"
|
||||
sidebarTitle: "Ollama"
|
||||
description: "Configure Ollama as an embedding provider in Mem0 to generate embeddings locally using open-source models."
|
||||
---
|
||||
You can use embedding models from Ollama to run Mem0 locally.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: OpenAI
|
||||
title: "OpenAI as Embedding Provider"
|
||||
sidebarTitle: "OpenAI"
|
||||
description: "Configure OpenAI as an embedding provider in Mem0 using models like text-embedding-3-large for vector generation."
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Together
|
||||
title: "Together AI as Embedding Provider"
|
||||
sidebarTitle: "Together"
|
||||
description: "Configure Together AI as an embedding provider in Mem0 with support for 1024-dimensional embedding models."
|
||||
---
|
||||
|
||||
@@ -10,7 +11,7 @@ To use Together embedding models, set the `TOGETHER_API_KEY` environment variabl
|
||||
<Note> The `embedding_model_dims` parameter for `vector_store` should be set to `1024` for Together embedder. </Note>
|
||||
|
||||
<Warning>
|
||||
**Breaking default change.** The default Together embedding model is now `intfloat/multilingual-e5-large-instruct` (**1024-dim**), replacing the previous default `togethercomputer/m2-bert-80M-8k-retrieval` (**768-dim**). If you created a self-hosted vector store with the old default, its collection is 768-dim and will reject the new 1024-dim vectors **recreate/reindex the collection at 1024 dimensions** after upgrading. To defer the change, pin the previous values explicitly (`model="togethercomputer/m2-bert-80M-8k-retrieval"`, `embedding_dims=768`) note Together no longer lists this model among its recommended embeddings, so reindexing at 1024 is the durable path.
|
||||
**Breaking default change.** The default Together embedding model is now `intfloat/multilingual-e5-large-instruct` (**1024-dim**), replacing the previous default `togethercomputer/m2-bert-80M-8k-retrieval` (**768-dim**). If you created a self-hosted vector store with the old default, its collection is 768-dim and will reject the new 1024-dim vectors — **recreate/reindex the collection at 1024 dimensions** after upgrading. To defer the change, pin the previous values explicitly (`model="togethercomputer/m2-bert-80M-8k-retrieval"`, `embedding_dims=768`) — note Together no longer lists this model among its recommended embeddings, so reindexing at 1024 is the durable path.
|
||||
</Warning>
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Overview
|
||||
title: "Embedding Providers Overview"
|
||||
sidebarTitle: Overview
|
||||
description: "Overview of all supported embedding model providers in Mem0, including OpenAI, Azure, Ollama, and more."
|
||||
---
|
||||
|
||||
@@ -15,15 +16,15 @@ See the list of supported embedders below.
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="OpenAI" icon="/images/provider-icons/openai.svg" href="/components/embedders/models/openai"></Card>
|
||||
<Card title="Azure OpenAI" icon="/images/provider-icons/azure-color.svg" href="/components/embedders/models/azure_openai"></Card>
|
||||
<Card title="Azure OpenAI" icon="/images/provider-icons/azure-color.svg" href="/components/embedders/models/azure-openai"></Card>
|
||||
<Card title="Ollama" icon="/images/provider-icons/ollama.svg" href="/components/embedders/models/ollama"></Card>
|
||||
<Card title="Hugging Face" icon="/images/provider-icons/huggingface.svg" href="/components/embedders/models/huggingface"></Card>
|
||||
<Card title="Google AI" icon="/images/provider-icons/google-color.svg" href="/components/embedders/models/google_AI"></Card>
|
||||
<Card title="Google AI" icon="/images/provider-icons/google-color.svg" href="/components/embedders/models/google-ai"></Card>
|
||||
<Card title="Vertex AI" icon="/images/provider-icons/vertexai.svg" href="/components/embedders/models/vertexai"></Card>
|
||||
<Card title="Together" icon="/images/provider-icons/together-color.svg" href="/components/embedders/models/together"></Card>
|
||||
<Card title="LM Studio" icon="/images/provider-icons/lmstudio.svg" href="/components/embedders/models/lmstudio"></Card>
|
||||
<Card title="Langchain" icon="/images/provider-icons/langchain-color.svg" href="/components/embedders/models/langchain"></Card>
|
||||
<Card title="AWS Bedrock" icon="/images/provider-icons/bedrock-color.svg" href="/components/embedders/models/aws_bedrock"></Card>
|
||||
<Card title="AWS Bedrock" icon="/images/provider-icons/bedrock-color.svg" href="/components/embedders/models/aws-bedrock"></Card>
|
||||
<Card title="FastEmbed" icon="/images/provider-icons/qdrant.svg" href="/components/embedders/models/fastembed"></Card>
|
||||
</CardGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Configurations
|
||||
title: "LLM Configuration Reference"
|
||||
sidebarTitle: "Configurations"
|
||||
description: "Reference for LLM configuration options in Mem0 for Python and TypeScript, including value precedence rules."
|
||||
---
|
||||
|
||||
@@ -133,4 +134,4 @@ Here's a comprehensive list of all parameters that can be used across different
|
||||
|
||||
## Supported LLMs
|
||||
|
||||
For detailed information on configuring specific LLMs, please visit the [LLMs](./models) section. There you'll find information for each supported LLM with provider-specific usage examples and configuration details.
|
||||
For detailed information on configuring specific LLMs, please visit the [LLMs](./overview) section. There you'll find information for each supported LLM with provider-specific usage examples and configuration details.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user