Six defects in 0.3.x plugin telemetry. Defects 1, 2 and 6 were not three bugs: they were one spool protocol getting three properties wrong. Identity was decided by the wrong process. `harness` was stamped in record(), correctly, but `source` was read from a module global in flush() — so whichever process drained the spool named every event in it. Two processes never call init(): mcp_server.py, and the detached `python3 telemetry.py` sender that spawn_flush() starts. record() now stamps source beside harness, and the build generates core/_harness_id.py per host so identity resolves with no init() call at all. That also unifies two defaults that disagreed (`<host>_plugin` vs `MEM0_<HOST>_PLUGIN`), which could yield three source values for one plugin. Ownership was inferred, not held. Path.replace is os.rename, which preserves mtime, so a claim made after a quiet minute inherited the spool's age and was stealable the instant it existed. Claims are touched on creation and the per-batch rewrite doubles as a lease heartbeat. Progress was not durable. flush() returned on the first failed batch without truncating, so the retry re-posted from index 0 — 150 events delivered 250 times. It now rewrites the claim with the unsent remainder after every batch, bounding a crash to one repeated batch, and each event carries a uuid. Parked batches starved. They were only reachable when no spool existed, and because sessions keep recording there usually was one, so a batch parked by a failed send waited until the 7-day expiry deleted it unsent — despite its own presence being what starts the sender. flush() drains them in the same run, and expiry now applies only after a genuine retry has failed. code.install counted upgrades and repeat sessions. is_first_run() read the identity file, which only a successful flush writes, so an offline user recorded an install every session forever. A dedicated install-state.json is claimed atomically at record time; a non-empty data directory reads as an upgrade. The docs called this anonymous. Every event carries the account email, and the hashes were unsalted SHA-256 over a git remote URL or an absolute path containing the username. READMEs, the module docstring and a new docs section now say what the code does, and repo/session digests are salted per install. A cached email outlived an API key change. It is now re-resolved when the key's fingerprint differs, and $identify aliases anonymous->email only — aliasing one account to another merges person profiles irreversibly. All six shipped green because the shared core's only tests lived under one host, behind a conftest that calls init() at import. Core behaviour was never exercised uninitialised. Adds agent-plugin-core/tests with no init, including subprocess tests and coverage for the portable plugin, which has no flush worker and would pass a native-only test vacuously. Also puts the three surface headers on the SDKs, CLIs and integrations, and corrects a README claiming ZAPIER/STRANDS were already in the platform allowlist. Verified: 59 core tests, 203 claude-code, 11 cursor, 5 codex, 2 kimi, 6 antigravity. ruff and compileall clean. --check clean for all six hosts. TypeScript changes are not typechecked locally (deps not installed). Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb
mem0 CLI
The official command-line interface for mem0 — the memory layer for AI agents. Works with the Mem0 Platform API. Available in Python and Node.js.
For AI agents: pass
--agent(or--json) on any command for structured JSON output purpose-built for tool loops — sanitized fields, no colors or spinners, errors as JSON. See Agent mode below.
Installation
npm install -g @mem0/cli
pip install mem0-cli
Both packages install a mem0 binary with identical behavior.
Quick start
# Interactive setup wizard
mem0 init
# Or login via email (get a new API key)
mem0 init --email alice@company.com
# Or authenticate with an existing API key
mem0 init --api-key m0-xxx
# Add a memory
mem0 add "I prefer dark mode and use vim keybindings" --user-id alice
# Search memories
mem0 search "What are Alice's preferences?" --user-id alice
# List all memories for a user
mem0 list --user-id alice
# Update a memory
mem0 update <memory-id> "I switched to light mode"
# Delete a memory
mem0 delete <memory-id>
Commands
| Command | Description |
|---|---|
mem0 init |
Setup wizard — login via email or configure API key manually |
mem0 add |
Add a memory from text, JSON messages, a file, or stdin |
mem0 search |
Search memories using natural language |
mem0 list |
List memories with optional filters and pagination |
mem0 get |
Retrieve a specific memory by ID |
mem0 update |
Update the text or metadata of a memory |
mem0 delete |
Delete a memory, all memories for a scope, or an entity |
mem0 import |
Bulk import memories from a JSON file |
mem0 config |
View or modify CLI configuration |
mem0 entity |
List or delete entities (users, agents, apps, runs) |
mem0 event |
Inspect background processing events (bulk deletes, large add jobs) |
mem0 status |
Verify API connection and display current project |
Run mem0 <command> --help for detailed usage on any command, or mem0 --version to print the CLI version.
Agent mode
Pass --agent (or its alias --json) as a global flag on any command to get output designed for AI agent tool loops:
mem0 --agent search "user preferences" --user-id alice
mem0 --agent add "User prefers dark mode" --user-id alice
mem0 --agent list --user-id alice
Every command returns the same envelope shape:
{
"status": "success",
"command": "search",
"duration_ms": 134,
"scope": { "user_id": "alice" },
"count": 2,
"data": [
{ "id": "abc-123", "memory": "User prefers dark mode", "score": 0.97, "created_at": "2026-01-15", "categories": ["preferences"] }
]
}
What agent mode does differently from --output json:
- Sanitized
data: only the fields an agent needs (id, memory, score, etc.) — no internal API noise - No human output: spinners, colors, and banners are suppressed entirely
- Errors as JSON: errors go to stdout as
{"status": "error", "command": "...", "error": "..."}with a non-zero exit code
Use mem0 help --json to get the full command tree as JSON — useful for agents that need to self-discover available commands.
Output formats
Control how results are displayed with --output:
| Format | Description |
|---|---|
text |
Human-readable with colors and formatting (default) |
json |
Structured JSON for piping to jq (raw API response) |
table |
Tabular format (default for list) |
quiet |
Minimal — just IDs or status codes |
agent |
Structured JSON envelope with sanitized fields (set by --agent/--json) |
Environment variables
| Variable | Description |
|---|---|
MEM0_API_KEY |
API key (overrides config file) |
MEM0_BASE_URL |
API base URL |
MEM0_USER_ID |
Default user ID |
MEM0_AGENT_ID |
Default agent ID |
MEM0_APP_ID |
Default app ID |
MEM0_RUN_ID |
Default run ID |
MEM0_ENABLE_GRAPH |
Enable graph memory (true / false) |
Implementations
| Language | Directory | Package | Docs |
|---|---|---|---|
| TypeScript | node/ |
@mem0/cli |
README |
| Python | python/ |
mem0-cli |
README |
Documentation
Full documentation is available at docs.mem0.ai/platform/cli.
License
Apache-2.0