Findings from an independent review of this branch. The exit-time flush was gated by its own cooldown. beforeExit called the same flush() that opens with a retryNotBefore check, so after any failed delivery a process exiting inside the 2s to 60s window sent nothing and the queue died with it. That is precisely the loss this branch exists to stop, and timer.unref makes beforeExit often the only remaining chance. flush(force) now skips the cooldown and beforeExit passes it. Overflow kept the newest and evicted the batch being retried, which threw away exactly the events the retry exists to save. Both the failure path and capture() now keep the backlog and drop the new event instead, matching Python's record(), which refuses new events once the spool is full. That change needs a bound, so delivery now gives up after five attempts, as the Python core does. Without one a payload the server will never accept would be retried for the whole session and, with the backlog now preferred, would hold the queue against everything behind it. Events carry a capture-time timestamp. They now sit through backoff and across an entire outage, so without one PostHog records them at whatever moment delivery happened to succeed. It also matters for the uuid dedupe, whose key includes the event date. openclaw wiped a resolved account on any capture without an apiKey: the fingerprint comparison was `undefined === ""`, so a keyless call looked like a key change. Guarded on a real key being present. Masked today because every call site supplies one, which is why only a test found it. Two smaller ones. opencode's PostHog source was "plugin", which named no particular plugin and matched no vocabulary; it is now OPENCODE_PLUGIN like every other surface, and a saved insight filtering source = "plugin" needs repointing. And an em dash in opencode's published description had been rewritten to a — escape by my own json.dumps when adding the test script; restored. One openclaw test asserted only not.toThrow() under a name claiming it checked the identity, and under the fingerprint gate the path it exercised no longer uses the email at all. It now pins the real condition. core 35, openclaw 432, opencode 35, pi-agent 89, deepseek 47. The wire e2e still passes 9 of 9 against a real local server, and the identity e2e 7 of 7. Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb
Mem0 agent plugin core
This directory is the single source of shared memory behavior for Mem0 coding-agent plugins. Installable plugins remain ordinary sibling directories under integrations/.
Architecture
integrations/
├── agent-plugin-core/ # Shared source; never installed as a plugin
│ ├── python/ # Claude-derived capture, recall, MCP, scoping, and telemetry
│ ├── typescript/ # Shared lifecycle, formatting, identity, scoping, and telemetry
│ ├── skills/ # The only source for the six generated memory skills
│ ├── build/ # Bundle builder, schemas, and validation
│ ├── conformance/ # One offline/live verification entry point
│ └── tests/
├── mem0-agent-plugin/ # One portable Agent Plugins v1 package
├── claude-code-plugin/ # Native Claude package and adapter
├── cursor-plugin/ # Native Cursor package and adapter
├── codex-plugin/ # Native Codex package and adapter
├── kimi-plugin/ # Native Kimi package and adapter
└── antigravity-plugin/ # Native Antigravity package and adapter
Each native directory owns only its manifest, native hooks or adapter, tests, and plugin-build.json. Its core/ and skills/ directories are generated from this module. They are committed because clients install a self-contained plugin directory and the Agent Plugins specification forbids package files from resolving outside the plugin root.
Sidekick belongs only to Claude Code. Its agent definition is in claude-code-plugin/agents/sidekick.md; its hooks are in claude-code-plugin/adapters/claude/hook.py. Other plugins must not register Sidekick. The shared core handles memory and native subagent tracking for Claude Code and Codex.
TypeScript integrations (openclaw, opencode-plugin, pi-agent-plugin, and deepseek-plugin) import typescript/src/ at build time. Their package builders include the shared implementation in their normal output; they do not carry checked-in copies.
Shared memory behavior
The six Python packages use the same search_memories MCP tool and six skill templates. Native hooks collect conversations and flush them to Mem0 in the background. The portable package uses the Agent Plugins v1 layout so compatible hosts can load its MCP server and skills. It has no lifecycle hooks or flush worker; its bundled remember skill assumes automatic capture and cannot save a memory on its own.
Python search accepts query, top_k, category, scope, and optional run_id:
| Scope | Memories searched |
|---|---|
repo (default) |
Shared repository memories and your personal memories in that repository |
dir |
Shared memories from the current directory and its children, plus your personal repository memories |
mine |
Your personal memories in that repository |
run_id filters any scope to memories saved in a known coding-agent session. Omit it for recall across sessions; it does not attribute the search request to the current session. Native Python extraction writes include the session's run_id.
New Git repository writes use a hashed remote identity for shared agent_id. Search and explicit shared-memory deletion include both that ID and the legacy unhashed ID under the same app_id. Legacy memories remain accessible, but their original ambiguity between matching owner/repository names on different Git hosts remains.
Captured prompts and responses preserve their full text after secret redaction. Python extraction splits oversized input across requests without dropping message text. The session-end worker flushes the conversation already collected by hooks without adding the final answer again. Search queries, retrieved context, and tool evidence have separate limits.
TypeScript hosts reuse redaction and lifecycle utilities but retain their own tools, scopes, and capture events. They do not inherit the Python repo/dir/mine contract or its background batching. OpenCode captures selected user prompts; Pi and DeepSeek capture completed conversation turns; OpenClaw selects recent messages and earlier summaries, then filters noise. Removing message-length truncation does not turn these integrations into complete transcript archives.
For installation, follow the host guides: Claude Code, Cursor, Codex, Kimi, and Antigravity.
Build and verify
From the repository root:
python3.11 -m venv /tmp/mem0-agent-plugins
/tmp/mem0-agent-plugins/bin/pip install \
-r integrations/agent-plugin-core/requirements-dev.txt
for host in claude-code cursor codex kimi antigravity; do
/tmp/mem0-agent-plugins/bin/python \
integrations/agent-plugin-core/build/build.py "$host" \
--kind native --check
done
/tmp/mem0-agent-plugins/bin/python \
integrations/agent-plugin-core/build/build.py mem0-agent-plugin \
--kind portable --check
Use --sync instead of --check after changing python/ or skills/. This only replaces generated core/ and skills/ content; it does not change manifests, adapters, tests, or the Claude sidekick.
Run every offline Python and TypeScript check and write one machine-readable report:
/tmp/mem0-agent-plugins/bin/python \
integrations/agent-plugin-core/conformance/run.py \
--install \
--report /tmp/mem0-plugin-conformance.json
For every TypeScript integration, this also builds the publishable package, verifies its required entry files, and rejects compiled artifacts that still import monorepo source. This keeps published plugins self-contained without committing their dist/ directories.
The offline suite does not contact Mem0 Platform. An explicit disposable key enables the inherited live scoping suite:
export MEM0_API_KEY="m0-disposable-test-key"
/tmp/mem0-agent-plugins/bin/python \
integrations/agent-plugin-core/conformance/run.py \
--group live-platform --live \
--report /tmp/mem0-plugin-live-conformance.json
Do not put a real key in source files, command history shared with others, or pull-request configuration.
Add a plugin
For another native Python host:
- Add
integrations/<host>-plugin/with its native manifest and the smallest adapter that translates host events. - Add
plugin-build.jsondeclaring the plugin-root variable and runtime files. - Add one adapter contract test.
- Register the host in
build/build.pyandconformance/run.py. - Run
--sync,--check, and the conformance command above.
Keep capture, recall, memory scoping, redaction, skill text, and telemetry in this shared module. Host directories should contain only behavior required by their native SDK.
For a TypeScript host, import the shared lifecycle modules directly and keep only native SDK registration in the integration. Do not advertise capture or compaction behavior unless the host exposes the necessary lifecycle seam. Sidekick is limited to Claude Code.
Host capture capabilities
| Host | Conversation capture | Tool outcomes | Subagent context and correlation |
|---|---|---|---|
| Claude Code | Incremental active transcript branch | Native success/failure hooks | Parent context; native agent ID |
| Cursor | Prompt and response hooks; duplicate responses suppressed | Native success/failure hooks | No plugin subagent hooks or agent declaration |
| Codex | Native prompt and final-response fields | Structured failure indicators when present; otherwise unknown | Parent context; native agent ID |
| Kimi | Prompt hooks and completed v2 wire output | Native success/failure hooks | No plugin subagent hooks or agent declaration |
| Antigravity | Incremental completed transcript messages, including later prompts | Native tool errors | No plugin subagent hooks or agent declaration |
| Portable v1 | Explicit memory skills | No native lifecycle hooks | No native subagent declaration |
Python status uses subagent_runs and last_subagent. Legacy SQLite names and event handling keep existing records and running workers compatible.
An uncorrelated subagent completion is kept as its own record; the plugin never guesses which overlapping run completed. Codex's documented hook fields already match the shared input contract, so no speculative field aliases or unsupported failure event are registered.
Offline conformance exercises the adapters and MCP servers with native-shaped payloads and builds each distributable package. It does not establish that every installed editor or Harness version loads the plugin correctly; those checks require smoke tests in the actual hosts.