A programmatic n8n community node wrapping the hosted Mem0 v3 REST API: add, search, get, get-many, update, delete, plus usableAsTool so the n8n AI Agent can call it. - Zero runtime dependencies (calls REST directly), TypeScript, ESLint clean — meets n8n verified-node requirements - Add supports custom_instructions, custom_categories, includes, excludes, a client-side entity-id guard, and async event polling (itemIndex on errors) - Anonymous opt-out telemetry (MEM0_TELEMETRY=false) - Docs page + docs.json/llms.txt entry, ci-gate + release wiring, AGENTS.md rows - Verified: tsc + ESLint + live E2E (add → search → get → delete) vs api.mem0.ai Split out of #6057 per review (separate PRs per integration).
29 KiB
AGENTS.md
This file provides context for AI coding assistants (Claude Code, Cursor, GitHub Copilot, Codex, etc.) working with the Mem0 repository.
Project Overview
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.
- Repository: https://github.com/mem0ai/mem0
- Documentation: https://docs.mem0.ai
- License: Apache-2.0
Repository Structure
This is a polyglot monorepo containing Python and TypeScript packages, CLIs, servers, plugins, and documentation.
Key Directories
| 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 |
server/ |
FastAPI REST server for self-hosted Mem0 (Docker: FastAPI + PostgreSQL/pgvector + Neo4j) |
openmemory/ |
Self-hosted memory platform — api/ (FastAPI + Alembic + MCP server) and ui/ (Next.js 15 + React 19) |
skills/ |
Claude Code skill definitions. Reference skills (SDK knowledge, always-on): mem0/, mem0-cli/, mem0-vercel-ai-sdk/. Pipeline skills (run on demand): mem0-integrate/, mem0-test-integration/, mem0-oss-to-platform/ |
docs/ |
Documentation site (Mintlify) |
tests/ |
Python SDK tests (pytest) |
evaluation/ |
Submodule → 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/) |
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/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)
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/andopenmemory/development
Initial Setup
# Python SDK
hatch shell dev_py_3_11 # creates environment with all deps
pre-commit install # install git hooks
# TypeScript packages
cd mem0-ts && pnpm install # TS SDK
cd cli/node && pnpm install # Node CLI
cd integrations/vercel-ai-sdk && pnpm install # Vercel AI provider
cd integrations/openclaw && pnpm install # OpenClaw plugin
Build, Lint, and Test Commands
Python SDK (mem0/)
# 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
- 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 installbefore committing
TypeScript SDK (mem0-ts/)
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
- Node: 20, 22 (CI-tested)
- Build: tsup (CJS + ESM)
- Test: jest
- Formatter: prettier
Python CLI (cli/python/)
cd cli/python
pip install -e ".[dev]" # dev install with ruff + pytest
ruff check . # lint
ruff format . # format
pytest # test
hatch build # build
- 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)
Node CLI (cli/node/)
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)
- Node: 18+ required
- Build: tsup (ESM)
- Linter: Biome (not ESLint, not Ruff)
- Test: vitest (not jest)
- Framework: Commander + Chalk + ora + cli-table3
Vercel AI SDK Provider (integrations/vercel-ai-sdk/)
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)
- Build: tsup (CJS + ESM)
- Lint: ESLint + Prettier
- Test: jest + vitest (edge/node configs)
OpenClaw Plugin (integrations/openclaw/)
cd integrations/openclaw
pnpm install
pnpm run build # tsup
pnpm run test # vitest run
- Build: tsup (ESM)
- Test: vitest (with Codecov in CI)
- Plugin manifest:
openclaw.plugin.json
Server (server/)
# Docker production build
cd server
make build # docker build -t mem0-api-server .
make run_local # docker run -p 8000:8000 with .env
# 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
- Framework: FastAPI with uvicorn (auto-reload in dev)
- Services: PostgreSQL with pgvector, Neo4j 5.x with APOC plugin
- Hot reload: Dev Dockerfile mounts
server/andmem0/for live changes
OpenMemory (openmemory/)
# Full stack via Docker Compose
cd openmemory
docker-compose up
# Qdrant: localhost:6333
# API (MCP): localhost:8765
# UI: localhost:3000
# Individual development
cd openmemory/api && uvicorn main:app --reload # FastAPI backend
cd openmemory/ui && npm run dev # Next.js frontend
# Tests
cd openmemory/api && pytest tests/ # API tests (e.g., test_mcp_server.py)
- API: FastAPI + Alembic (DB migrations) + MCP server (Model Context Protocol)
- UI: Next.js 15, React 19, Radix UI, Redux Toolkit, TailwindCSS, Recharts
- Vector store: Qdrant
Documentation (docs/)
make docs # or: cd docs && mintlify dev
- 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 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:
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.pyabstract class in their directory. Config classes live inconfigs.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. - Ruff excludes
openmemory/from root config.
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:
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 - Local: MCP server in
openmemory/api/(FastAPI-based) - Plugin: MCP tools in
integrations/mem0-plugin/— 9 tools:add_memory,search_memories,get_memories,get_memory,update_memory,delete_memory,delete_all_memories,delete_entities,list_entities
Plugin & 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-integratewires Mem0 into an existing repo via a TDD pipeline;mem0-test-integrationverifies what the integrator produced on the same branch (the two are loosely coupled via.mem0-integration/artifacts);mem0-oss-to-platformmigrates an existing project from Mem0 OSS to the hosted Platform SDK (plan, then execute on approval).
- Reference skills (always-on SDK knowledge):
Adding a New Provider
To add a new LLM, embedding, vector store, or reranker provider:
- Create
mem0/<category>/<provider_name>.py - Inherit from the abstract base class in
mem0/<category>/base.py - Add configuration to
mem0/<category>/configs.py(if the category uses one) - Register the provider in
mem0/<category>/__init__.py - Add tests in
tests/<category>/<provider_name>/ - Add any new dependencies to the appropriate optional group in
pyproject.toml(never to coredependencies) - 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:
- Create
integrations/<name>/and build the integration there. - If it publishes to a registry, set
repository.directory: "integrations/<name>"in itspackage.jsonso npm provenance links to the correct subdirectory. - Add CI/CD under
.github/workflows/(<name>-checks.yml,<name>-cd.yml). Useintegrations/<name>inpaths:triggers,working-directory, andcache-dependency-path. Register the release tag prefix in thecaseblock inrelease.yml(keep the barev*arm last). Keep workflow filenames stable — npm OIDC trusted publishing is pinned to repo + workflow filename. - If it is a Claude Code / editor marketplace plugin, register its path in the five
marketplace.jsonfiles (root +.claude-plugin/,.cursor-plugin/,.codex-plugin/,.agents/plugins/). - Document it under
docs/integrations/and add the page todocs/docs.jsonanddocs/llms.txt. - Add rows to the "Key Directories" table and the CI/CD tables in this file.
CI/CD
CI Workflows (automated testing)
PR testing is orchestrated by a single entry point: ci-gate.yml (CI Gate) runs on every PR, detects which packages changed, and invokes only the relevant package workflows below as reusable workflows (workflow_call). Its final CI Gate job aggregates the results (skipped pipelines pass; failed or cancelled ones fail) and is the only status check that needs to be required in branch protection. Package workflows keep their own push-to-main and manual triggers; their pull_request triggers moved into the gate's path filters.
| Workflow | File | Standalone Triggers | Tests |
|---|---|---|---|
| CI Gate | ci-gate.yml |
All PRs | Routes to and aggregates the workflows below |
| Python SDK | ci.yml |
Push to main | Ruff lint + pytest on Python 3.10, 3.11, 3.12 |
| TypeScript SDK | ts-sdk-ci.yml |
Push to main (on mem0-ts/) |
Prettier + build + jest on Node 20, 22 |
| Python CLI | cli-python-ci.yml |
Push to main (on cli/python/), manual |
Ruff lint + pytest + hatch build on Python 3.10, 3.11, 3.12 |
| Node CLI | cli-node-ci.yml |
Push to main (on cli/node/), manual |
Biome lint + tsc + vitest + tsup build on Node 20, 22 |
| OpenClaw | openclaw-checks.yml |
Push to main (on integrations/openclaw/), manual |
tsc + vitest (with Codecov) + tsup build on Node 20, 22 |
| OpenCode Plugin | opencode-plugin-checks.yml |
Push to main (on integrations/mem0-plugin/.opencode-plugin/), manual |
Bun: tsc type-check + build + dist artifact check |
| Pi Agent Plugin | pi-agent-plugin-checks.yml |
Push to main (on integrations/pi-agent-plugin/), manual |
tsc + vitest + tsup build (dist artifact check) on Node 20, 22 |
| 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 |
| 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 (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>. - When adding a new package: add its CD workflow (
workflow_dispatchwithtag/prereleaseinputs), then register its tag prefix in thecaseblock inrelease.yml. Keep the barev*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
- Unit tests: Add tests that would fail without the fix (regression tests)
- Implementation: Fix the bug
- Manual verification: Run the relevant test suite to confirm the fix
- Lint: Run the appropriate linter for the package you modified
New Features
- Implementation: Build the feature following existing patterns
- Unit tests: Comprehensive test coverage for new functionality
- Documentation: Update relevant docs in
docs/for public APIs - Examples: Add usage examples if the feature introduces new user-facing behavior
- llms.txt: Any new
.mdxpage underdocs/must be linked indocs/llms.txtwith a scope tag ([Platform]/[OSS]/[Both]) and aUse when ...description. Thedocs-llms-txt-check.ymlworkflow runs on every PR that touches docs and fails the check if the index is out of sync. To fix: runpython scripts/check-llms-txt-coverage.py --writelocally to scaffold placeholders under## Unclassified - needs triage, then replace the[TODO: ...]tags, rewrite descriptions asUse when ..., move entries into the right section, and delete the triage heading when empty.
New Provider (LLM / Embedding / Vector Store / Reranker)
- Implementation: Follow the "Adding a New Provider" steps above
- Tests: Add unit tests matching the pattern of existing providers
- Configuration: Add to the appropriate
configs.pyand__init__.py - Dependencies: Add to the correct optional group in
pyproject.toml - 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
- Fork and clone the repository.
- Create a feature branch from
main(e.g.,feature/my-new-feature). - Make your changes — add tests, docs, and examples as appropriate.
- Run linting and tests for every package you modified (see commands above).
- Run
pre-commit installon first setup — hooks run ruff + isort automatically. - Commit with a clear message following Conventional Commits (e.g.,
feat:,fix:,docs:,refactor:). - 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):
- Linked Issue — Reference the issue with
Closes #<number>. If no issue exists, create one first or explain why in the description. - Description — Explain what the PR does and why it's needed.
- Type of Change — Check the appropriate box:
- Bug fix / New feature / Breaking change / Refactor / Documentation update
- Breaking Changes — If applicable, describe what breaks and the migration path.
- Test Coverage — Check what applies:
- Added/updated unit tests
- Added/updated integration tests
- Tested manually (describe how)
- No tests needed (explain why)
- 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
## 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) orpackage.json(TypeScript). - For
server/andopenmemory/work, use Docker Compose for local development. - Do NOT use
piporcondafor dependency management — usehatch(seedocs/contributing/development.mdx).
Contributing Guides
| Task | Guide |
|---|---|
| Code contributions | 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
dependencieslist inpyproject.tomlwithout discussion — use optional dependency groups instead. - Commit
.envfiles, 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 moduleimportsyntax. - Mix up linter configs: root Python SDK uses line-length 120, Python CLI uses 100, Node CLI uses Biome (not ESLint/Ruff).
- Modify
openmemory/database migrations without understanding the Alembic migration chain. - Change public APIs without updating documentation in
docs/.