---
title: "Plugin Conformance Testing"
description: "Plugin conformance testing provides a unified verification framework to validate coding-agent memory plugins, ensuring bundle integrity, contract adherence, and cross-platform runtime stability acr..."
last_updated: "2026-10-11T17:37:10.224265+00:00"
canonical_url: "https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/telemetry-ops/plugin-conformance-testing"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [integrations/agent-plugin-core/conformance/run.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py)
- [integrations/agent-plugin-core/python/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/python/memory_core.py)
- [integrations/claude-code-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/memory_core.py)
- [integrations/claude-code-plugin/core/hook_runner.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py)
- [integrations/agent-plugin-core/python/hook_runner.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/python/hook_runner.py)
- [integrations/antigravity-plugin/core/hook_runner.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/core/hook_runner.py)
- [integrations/codex-plugin/core/hook_runner.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/hook_runner.py)
- [integrations/cursor-plugin/core/hook_runner.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/core/hook_runner.py)
- [integrations/codex-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/memory_core.py)
- [integrations/mem0-agent-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/memory_core.py)
- [integrations/antigravity-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/core/memory_core.py)
- [integrations/cursor-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/core/memory_core.py)
- [integrations/kimi-plugin/core/memory_core.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/core/memory_core.py)
- [integrations/agent-plugin-core/conformance/artifacts.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py)
- [integrations/claude-code-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/memory_cli.py)
- [integrations/mem0-agent-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/memory_cli.py)
- [integrations/agent-plugin-core/python/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/python/memory_cli.py)
- [integrations/deepseek-plugin/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/deepseek-plugin/src/index.ts)
- [integrations/openclaw/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/openclaw/index.ts)
- [integrations/antigravity-plugin/hooks/adapter.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/hooks/adapter.py)
- [integrations/codex-plugin/hooks/adapter.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/hooks/adapter.py)
- [integrations/claude-code-plugin/core/_harness_id.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/_harness_id.py)
- [integrations/antigravity-plugin/hooks.json](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/hooks.json)
- [integrations/cursor-plugin/hooks/adapter.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py)
- [integrations/codex-plugin/core/_harness_id.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/_harness_id.py)
- [integrations/mem0-agent-plugin/core/_harness_id.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/_harness_id.py)
- [integrations/claude-code-plugin/adapters/claude/hook.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/adapters/claude/hook.py)
- [integrations/kimi-plugin/hooks/adapter.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py)
- [integrations/antigravity-plugin/core/_harness_id.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/core/_harness_id.py)
</details>

## Overview

Plugin conformance testing provides a unified verification framework to validate coding-agent memory plugins, ensuring bundle integrity, contract adherence, and cross-platform runtime stability across Python and TypeScript implementations. The suite systematically exercises both the shared core logic and individual plugin wrappers to guarantee that interactions with host environments remain predictable and consistent.

Sources: [integrations/agent-plugin-core/conformance/run.py:1-30](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L1-L30), [integrations/agent-plugin-core/conformance/artifacts.py:1-24](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L1-L24)

The framework coordinates automated test suites, command execution checks, and artifact inspections for hosts such as [Claude Code Plugin](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/claude-code-plugin), Cursor, Codex, Kimi, and Antigravity, alongside portable plugins and platform integrations. It prevents subtle behavioral divergence across the diverse host environments by establishing strict runtime and build constraints that each implementation must satisfy.

Sources: [integrations/agent-plugin-core/conformance/run.py:19-29](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L19-L29), [integrations/agent-plugin-core/conformance/artifacts.py:15-23](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L15-L23)

By centralizing test orchestration, artifact validation, hook normalization contracts, and harness segregation checks into a single runner architecture, the test suite catches regression issues and verifies distribution readiness prior to deployment. This guarantees that built plugins remain self-contained, free of monorepo path leaks, and fully capable of operating within host-specific sandbox limitations.

Sources: [integrations/agent-plugin-core/conformance/run.py:38-133](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L38-L133), [integrations/agent-plugin-core/conformance/artifacts.py:29-44](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L29-L44)

## Conformance Suite Test Runner Architecture

### Suite Orchestration and Python Hosts

The conformance runner uses Python path resolution via `CORE_ROOT` and `REPOSITORY_ROOT` to locate plugin directories, importing `redact` from `memory_core`, `build` from `build.build`, and artifact verifiers from `conformance.artifacts`. Python host integrations cover five coding-agent environments: `claude-code`, `cursor`, `codex`, `kimi`, and `antigravity`.

```python
CORE_ROOT = Path(__file__).resolve().parents[1]
REPOSITORY_ROOT = CORE_ROOT.parents[1]
PYTHON_HOSTS = ("claude-code", "cursor", "codex", "kimi", "antigravity")
GROUPS = (
    "python-bundles",
    "python-tests",
    "typescript-core",
    "openclaw",
    "opencode",
    "pi-agent",
    "deepseek",
)
LIVE_GROUP = "live-platform"

sys.path.insert(0, str(CORE_ROOT))
sys.path.insert(0, str(CORE_ROOT / "python"))
from memory_core import redact  # noqa: E402
from build.build import build  # noqa: E402
from conformance.artifacts import TYPESCRIPT_ARTIFACTS, verify_artifact as _typescript_artifact_check  # noqa: E402
```
Sources: [integrations/agent-plugin-core/conformance/run.py:17-36](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L17-L36)

Group execution encompasses seven static validation groups alongside a live platform integration target.

| Group Name | Target Environment / Tooling | Associated Commands / Artifacts | Sources |
| :--- | :--- | :--- | :--- |
| `python-bundles` | Python hosts & portable bundle | Native host builds & `mem0-agent-plugin` portable build | [integrations/agent-plugin-core/conformance/run.py:19-21](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L19-L21), [integrations/agent-plugin-core/conformance/run.py:101-110](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L101-L110) |
| `python-tests` | Shared Python test suite | `pytest integrations/agent-plugin-core/tests` (plus host tests, ignoring conformance and integration tests) | [integrations/agent-plugin-core/conformance/run.py:22](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L22), [integrations/agent-plugin-core/conformance/run.py:50-65](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L50-L65) |
| `typescript-core` | [TypeScript Agent Core](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/typescript-agent-core) | `pnpm test`, `pnpm typecheck` | [integrations/agent-plugin-core/conformance/run.py:23](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L23), [integrations/agent-plugin-core/conformance/run.py:66](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L66) |
| `openclaw` | [OpenClaw integration](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/openclaw-integration) | `pnpm test`, `pnpm exec tsc --noEmit`, `pnpm build` + required artifacts | [integrations/agent-plugin-core/conformance/run.py:24](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L24), [integrations/agent-plugin-core/conformance/run.py:67-71](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L67-L71) |
| `opencode` | OpenCode plugin | `bun test`, `bun run type-check`, `bun run build` + required artifacts | [integrations/agent-plugin-core/conformance/run.py:25](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L25), [integrations/agent-plugin-core/conformance/run.py:72-76](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L72-L76) |
| `pi-agent` | Pi-Agent plugin | `pnpm test`, `pnpm typecheck`, `pnpm build` + required artifacts | [integrations/agent-plugin-core/conformance/run.py:26](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L26), [integrations/agent-plugin-core/conformance/run.py:77-81](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L77-L81) |
| `deepseek` | DeepSeek plugin | `pnpm test`, `pnpm typecheck`, `pnpm build` + required artifacts | [integrations/agent-plugin-core/conformance/run.py:27](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L27), [integrations/agent-plugin-core/conformance/run.py:82-86](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L82-L86) |
| `live-platform` | Claude Code integration tests | `pytest integrations/claude-code-plugin/tests/integration -q` | [integrations/agent-plugin-core/conformance/run.py:29](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L29), [integrations/agent-plugin-core/conformance/run.py:87-95](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L87-L95) |

Sources: [integrations/agent-plugin-core/conformance/run.py:19-96](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L19-L96)

### Check Planning and Execution

The check planning phase dynamically aggregates tasks based on selected groups. For `python-bundles`, it schedules native and portable bundle targets across all defined python hosts. For runtime command groups, it maps each command entry to a numbered check identifier and appends artifact verification checks if the group exists in `TYPESCRIPT_ARTIFACTS`.

```python
def _planned_checks(groups: set[str]) -> list[dict[str, Any]]:
    checks: list[dict[str, Any]] = []
    if "python-bundles" in groups:
        checks.append(
            {
                "name": "python-bundles",
                "group": "python-bundles",
                "status": "planned",
                "hosts": list(PYTHON_HOSTS),
                "kinds": {"native": list(PYTHON_HOSTS), "portable": ["mem0-agent-plugin"]},
            }
        )
    for group, commands in _runtime_commands().items():
        if group not in groups:
            continue
        for index, command in enumerate(commands, start=1):
            checks.append(
                {
                    "name": f"{group}-{index}",
                    "group": group,
                    "status": "planned",
                    "command": command,
                }
            )
        if group in TYPESCRIPT_ARTIFACTS:
            _, required = TYPESCRIPT_ARTIFACTS[group]
            checks.append(
                {
                    "name": f"{group}-artifact",
                    "group": group,
                    "status": "planned",
                    "required": list(required),
                }
            )
    return checks
```
Sources: [integrations/agent-plugin-core/conformance/run.py:99-133](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L99-L133)

Command execution is handled by `_command_check`, which records monotonic duration, merges environment overrides, and redacts sensitive data from both the command arguments and captured standard output and error streams. Output capture truncates the response text to the final 8,000 characters when populated.

```python
def _command_check(
    name: str,
    group: str,
    command: list[str],
    *,
    cwd: Path,
    environment_overrides: dict[str, str] | None = None,
) -> dict[str, Any]:
    started = time.monotonic()
    environment = dict(os.environ)
    environment.update(environment_overrides or {})
    safe_command = [redact(part) for part in command]
    try:
        result = subprocess.run(
            command,
            cwd=cwd,
            env=environment,
            text=True,
            capture_output=True,
            check=False,
        )
        output = redact((result.stdout + result.stderr).strip())
        return {
            "name": name,
            "group": group,
            "status": "passed" if result.returncode == 0 else "failed",
            "duration_seconds": round(time.monotonic() - started, 3),
            "command": safe_command,
            "exit_code": result.returncode,
            **({"output": output[-8_000:]} if output else {}),
        }
    except OSError as exc:
        return {
            "name": name,
            "group": group,
            "status": "failed",
            "duration_seconds": round(time.monotonic() - started, 3),
            "command": safe_command,
            "exit_code": None,
            "output": redact(str(exc)),
        }
```
Sources: [integrations/agent-plugin-core/conformance/run.py:136-177](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L136-L177)

> [!NOTE]
> Command checks execute with `check=False` to capture non-zero exit codes as failed status outcomes without throwing exceptions prematurely during test suite execution.

Sources: [integrations/agent-plugin-core/conformance/run.py:149-166](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/run.py#L149-L166)

## Artifact Validation and Build Inspection

### TypeScript Artifact Definitions

The conformance framework verifies that built TypeScript packages contain all required distribution files and do not leak internal monorepo dependencies. The `TYPESCRIPT_ARTIFACTS` mapping defines the root paths and mandatory build outputs for each integration package.

| Plugin Group | Package Path | Required Artifacts |
| :--- | :--- | :--- |
| `openclaw` | `integrations/openclaw` | `dist/index.js`, `dist/index.d.ts` |
| `opencode` | `integrations/opencode-plugin` | `dist/index.js`, `index.d.ts` |
| `pi-agent` | `integrations/pi-agent-plugin` | `dist/index.js`, `dist/index.d.ts`, `dist/entry.js`, `dist/entry.d.ts` |
| `deepseek` | `integrations/deepseek-plugin` | `dist/index.js`, `dist/index.d.ts` |

```python
TYPESCRIPT_ARTIFACTS = {
    "openclaw": (INTEGRATIONS_ROOT / "openclaw", ("dist/index.js", "dist/index.d.ts")),
    "opencode": (INTEGRATIONS_ROOT / "opencode-plugin", ("dist/index.js", "index.d.ts")),
    "pi-agent": (
        INTEGRATIONS_ROOT / "pi-agent-plugin",
        ("dist/index.js", "dist/index.d.ts", "dist/entry.js", "dist/entry.d.ts"),
    ),
    "deepseek": (INTEGRATIONS_ROOT / "deepseek-plugin", ("dist/index.js", "dist/index.d.ts")),
}
```
Sources: [integrations/agent-plugin-core/conformance/artifacts.py:15-23](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L15-L23)

### Verification Logic and Monorepo Leak Detection

The `verify_artifact` function checks for the physical presence of every required file within the package directory. It then recursively scans compiled JavaScript and declaration files (`*.js`, `*.mjs`, `*.cjs`, `*.d.ts`) inside the `dist` directory using a regular expression pattern that detects unbundled monorepo imports referencing `agent-plugin-core`.

```python
MONOREPO_IMPORT = re.compile(
    r"(?:from\s+|import\s*\(|require\s*\()\s*['\"][^'\"]*agent-plugin-core"
)


def verify_artifact(group: str, package: Path, required: tuple[str, ...]) -> dict[str, Any]:
    started = time.monotonic()
    errors = [f"missing package artifact: {name}" for name in required if not (package / name).is_file()]
    dist = package / "dist"
    for pattern in ("*.js", "*.mjs", "*.cjs", "*.d.ts"):
        for artifact in dist.rglob(pattern) if dist.is_dir() else ():
            if MONOREPO_IMPORT.search(artifact.read_text(encoding="utf-8")):
                errors.append(f"monorepo source import in package artifact: {artifact.relative_to(package)}")
    return {
        "name": f"{group}-artifact",
        "group": group,
        "status": "failed" if errors else "passed",
        "duration_seconds": round(time.monotonic() - started, 3),
        **({"output": "\n".join(errors)} if errors else {}),
    }
```
Sources: [integrations/agent-plugin-core/conformance/artifacts.py:24-43](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L24-L43)

> [!WARNING]
> Any matching `agent-plugin-core` import found inside built distribution files causes the artifact verification check to fail, ensuring that distributed packages remain entirely self-contained.

Sources: [integrations/agent-plugin-core/conformance/artifacts.py:33-36](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/agent-plugin-core/conformance/artifacts.py#L33-L36)

## Python Hook Runner Contract Conformance

### Hook Input Handling and Session Orchestration

The shared Python hook runner implementations across agent variants orchestrate event hooks via standard input parsing and background worker handoffs (see [Python Agent Core](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/python-agent-core)). The `read_hook_input` function parses JSON payloads from standard input, returning an empty dictionary upon encountering `json.JSONDecodeError` or `OSError`.

```python
def read_hook_input() -> dict:
    try:
        value = json.load(sys.stdin)
        return value if isinstance(value, dict) else {}
    except (json.JSONDecodeError, OSError):
        return {}
```
Sources: [integrations/claude-code-plugin/core/hook_runner.py:44-50](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L44-L50)

| Constant | Value | Purpose |
| :--- | :--- | :--- |
| `STALE_RUNNING_SECONDS` | `300` | Threshold in seconds before a running handoff file is considered stale and reset. |
| `PENDING_EXPIRY_SECONDS` | `604800` (7 days) | Maximum age for pending handoff files before unlinking. |
| `PENDING_LAUNCH_LIMIT` | `5` | Maximum number of pending handoffs launched per recovery cycle. |
| `DEFAULT_IDLE_FLUSH_SECONDS` | `300` | Default idle duration triggering flush execution. |

```python
STALE_RUNNING_SECONDS = 300
PENDING_EXPIRY_SECONDS = 7 * 24 * 60 * 60
PENDING_LAUNCH_LIMIT = 5
DEFAULT_IDLE_FLUSH_SECONDS = 300
```
Sources: [integrations/claude-code-plugin/core/hook_runner.py:36-40](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L36-L40)

> [!NOTE]
> Automatic flushing relies on `MEM0_CODE_AUTO_FLUSH` environment variable settings, matching values `"1"`, `"true"`, `"yes"`, or `"on"` case-insensitively.

Sources: [integrations/claude-code-plugin/core/hook_runner.py:193-196](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L193-L196)

### First Prompt Memory Injection and Handoff Lifecycle

When evaluating initial user prompts, `first_prompt_memory_output` retrieves query parameters from environment variables and checks length bounds before querying vector stores.

```python
def first_prompt_memory_output(store: EvidenceStore, hook_input: dict) -> dict:
    """Search once before the agent handles the first prompt in a session."""
    repo, session_id, prompt, is_first_prompt = record_user_prompt(store, hook_input)
    if not is_first_prompt:
        return {}
    try:
        minimum_query_chars = int(os.environ.get("MEM0_CODE_MIN_QUERY_CHARS", "20"))
    except ValueError:
        minimum_query_chars = 20
    if len(prompt.strip()) < max(minimum_query_chars, 1):
        return {}
    result = search_memories(
        store, repo, session_id, bounded(prompt, 6000),
        top_k=5, operation="first-prompt-search", timeout=2,
    )
```
Sources: [integrations/claude-code-plugin/core/hook_runner.py:62-76](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L62-L76)

```mermaid
sequenceDiagram
    participant Hook as hook_runner.py
    participant Store as EvidenceStore
    participant Worker as flush_worker.py

    Hook->>Store: record_user_prompt(hook_input)
    alt is_first_prompt and query length >= minimum_query_chars
        Hook->>Store: search_memories(prompt, top_k=5)
        Store-->>Hook: MemoryResult
        Hook->>Telemetry: record("context_injected")
        Hook-->>Agent: hookSpecificOutput (additionalContext)
    else subsequent prompt or short query
        Hook-->>Agent: {}
    end
    Note over Hook,Worker: Background Handoff
    Hook->>Worker: hand_off_flush() -> _launch_handoff()
```
Sources: [integrations/claude-code-plugin/core/hook_runner.py:64-94](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L64-L94), [integrations/claude-code-plugin/core/hook_runner.py:170-191](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L170-L191)

> [!WARNING]
> Handoff files are written atomically using a `.tmp` suffix before replacing the target `.json` file to prevent partial read states during concurrent worker launches.

Sources: [integrations/claude-code-plugin/core/hook_runner.py:180-190](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/hook_runner.py#L180-L190)

## Plugin Adapter Hook Normalization Testing

### Native Event Mapping and Payload Translation

Plugin adapters translate proprietary agent harness event streams into standardized arguments for the shared Mem0 runtime. Each adapter processes raw JSON inputs from standard input and maps harness-specific keys to common payload structures recognized by `hook_runner` and `memory_core`.

| Adapter Plugin | Native Event / Trigger | Mapped Runtime Action | Target Source / File |
| :--- | :--- | :--- | :--- |
| `cursor-plugin` | `sessionStart` | `session-start` | [integrations/cursor-plugin/hooks/adapter.py:26](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L26) |
| `cursor-plugin` | `beforeSubmitPrompt` | `user-prompt` | [integrations/cursor-plugin/hooks/adapter.py:27](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L27) |
| `cursor-plugin` | `postToolUse` | `post-tool` | [integrations/cursor-plugin/hooks/adapter.py:28](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L28) |
| `cursor-plugin` | `postToolUseFailure` | `post-tool-failure` | [integrations/cursor-plugin/hooks/adapter.py:29](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L29) |
| `cursor-plugin` | `afterAgentResponse` | `assistant-stop` | [integrations/cursor-plugin/hooks/adapter.py:30](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L30) |
| `cursor-plugin` | `stop` | `stop` | [integrations/cursor-plugin/hooks/adapter.py:31](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L31) |
| `cursor-plugin` | `sessionEnd` | `flush --reason session-end` | [integrations/cursor-plugin/hooks/adapter.py:32](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L32) |
| `cursor-plugin` | `preCompact` | `flush --reason pre-compact` | [integrations/cursor-plugin/hooks/adapter.py:33](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L33) |
| `kimi-plugin` | `SessionStart` | `session-start` | [integrations/kimi-plugin/hooks/adapter.py:23](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L23) |
| `kimi-plugin` | `UserPromptSubmit` | `user-prompt` | [integrations/kimi-plugin/hooks/adapter.py:24](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L24) |
| `kimi-plugin` | `PostToolUse` | `post-tool` | [integrations/kimi-plugin/hooks/adapter.py:25](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L25) |
| `kimi-plugin` | `PostToolUseFailure` | `post-tool-failure` | [integrations/kimi-plugin/hooks/adapter.py:26](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L26) |
| `kimi-plugin` | `Stop` | `stop` | [integrations/kimi-plugin/hooks/adapter.py:27](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L27) |
| `kimi-plugin` | `PreCompact` | `flush --reason pre-compact` | [integrations/kimi-plugin/hooks/adapter.py:28](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L28) |
| `kimi-plugin` | `SessionEnd` | `flush --reason session-end` | [integrations/kimi-plugin/hooks/adapter.py:29](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L29) |

Sources: [integrations/cursor-plugin/hooks/adapter.py:25-34](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/hooks/adapter.py#L25-L34), [integrations/kimi-plugin/hooks/adapter.py:22-30](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L22-L30)

> [!NOTE]
> The `antigravity-plugin` adapter configures execution through `hooks.json` mapping `PreInvocation`, `PostToolUse`, and `Stop` commands directly to `adapter.py` entry points with strict timeout limits.

Sources: [integrations/antigravity-plugin/hooks.json:3-16](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/hooks.json#L3-L16)

### Transcript Stream Parsing and Session Reconstruction

Adapters for harnesses like Antigravity and Kimi Code inspect local transcript file paths to extract structured conversation turns when direct message fields are missing from hook payloads. The Antigravity adapter reads newline-delimited JSON step objects, filtering for items where `status == "DONE"` and extracting redacted user requests enclosed within `<USER_REQUEST>` tags or planner response models.

```python
def _read_transcript(path: str) -> list[dict[str, str]]:
    messages = []
    try:
        with open(path, encoding="utf-8") as transcript:
            for line in transcript:
                try:
                    step = json.loads(line)
                except json.JSONDecodeError:
                    continue
                content = step.get("content")
                if not isinstance(content, str) or step.get("status") != "DONE":
                    continue
                if step.get("type") == "USER_INPUT":
                    match = re.search(r"<USER_REQUEST>\s*(.*?)\s*</USER_REQUEST>", content, re.DOTALL)
                    messages.append({"role": "user", "content": redact(match.group(1) if match else content).strip()})
                elif step.get("source") == "MODEL" and step.get("type") == "PLANNER_RESPONSE":
                    messages.append({"role": "assistant", "content": redact(content).strip()})
    except (OSError, TypeError):
        pass
    return messages
```
Sources: [integrations/antigravity-plugin/hooks/adapter.py:28-47](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/hooks/adapter.py#L28-L47)

Similarly, the Kimi Code adapter resolves session directories through `session_index.jsonl` lookups or globbing under `sessions/*/` to locate wire transcripts (`wire.jsonl`), aggregating text parts across loop events while skipping error or interrupted finish reasons.

```python
def _session_dir(session_id: str) -> Path | None:
    home = Path(os.environ.get("KIMI_CODE_HOME", Path.home() / ".kimi-code")).expanduser()
    found = None
    try:
        with (home / "session_index.jsonl").open(encoding="utf-8") as index:
            for line in index:
                try:
                    entry = json.loads(line)
                except json.JSONDecodeError:
                    continue
                if entry.get("sessionId") == session_id and isinstance(entry.get("sessionDir"), str):
                    found = Path(entry["sessionDir"])
    except OSError:
        pass
    if found:
        return found
    if not session_id or Path(session_id).name != session_id:
        return None
    return next((path for path in (home / "sessions").glob(f"*/{session_id}") if path.is_dir()), None)


def _last_assistant_message(transcript: Path) -> str:
    message = ""
    step_id = None
    parts = []
    try:
        lines = transcript.read_text(encoding="utf-8").splitlines()
    except OSError:
        return ""
    for line in lines:
        try:
            record = json.loads(line)
        except json.JSONDecodeError:
            continue
        if record.get("type") != "context.append_loop_event" or not isinstance(record.get("event"), dict):
            continue
        event = record["event"]
        if event.get("type") == "step.begin":
            step_id = event.get("uuid")
            parts = []
        elif event.get("type") == "content.part" and event.get("stepUuid") == step_id:
            part = event.get("part")
            if isinstance(part, dict) and part.get("type") == "text" and isinstance(part.get("text"), str):
                parts.append(part["text"])
        elif event.get("type") == "step.end" and event.get("uuid") == step_id:
            if event.get("finishReason") not in {"error", "interrupted"} and parts:
                message = "".join(parts)
            step_id = None
            parts = []
    return message
```
Sources: [integrations/kimi-plugin/hooks/adapter.py:33-82](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L33-L82)

> [!WARNING]
> Transcript parsing fails silently on `OSError`, `TypeError`, or `json.JSONDecodeError`, returning empty message lists or falling back to default runner implementations to prevent hook crashes.

Sources: [integrations/antigravity-plugin/hooks/adapter.py:35-46](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/hooks/adapter.py#L35-L46), [integrations/kimi-plugin/hooks/adapter.py:38-61](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/hooks/adapter.py#L38-L61)

## Harness Identity and Multi-Agent Environments

### Harness Identity Configuration and Source Tagging

The plugin core initializes runtime behavior using harness-specific identity parameters. Through `configure_harness`, plugins define their unique execution context including `name`, `env_prefix`, `data_dir_name`, and `source_tag`. When left unconfigured, defaults fallback to `generic` with standard `MEM0_PLUGIN` environment variables.

| Harness Identifier | Platform Source | Platform Application | Source Reference |
| :--- | :--- | :--- | :--- |
| `claude-code` | `MEM0_PLUGIN` | `claude-code` | [integrations/claude-code-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/_harness_id.py#L3-L11) |
| `codex` | `MEM0_PLUGIN` | `codex` | [integrations/codex-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/_harness_id.py#L3-L11) |
| `coding-agent` | `MEM0_PLUGIN` | *None* | [integrations/mem0-agent-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/_harness_id.py#L3-L11) |
| `antigravity` | `MEM0_PLUGIN` | `antigravity` | [integrations/antigravity-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/core/_harness_id.py#L3-L11) |

Sources: [integrations/claude-code-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/_harness_id.py#L3-L11), [integrations/codex-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/_harness_id.py#L3-L11), [integrations/mem0-agent-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/_harness_id.py#L3-L11), [integrations/antigravity-plugin/core/_harness_id.py:3-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-plugin/core/_harness_id.py#L3-L11)

> [!NOTE]
> The platform-side vocabulary separates the overarching source family (`MEM0_PLUGIN`) from the specific editor application header (`X-Application`). If the application field is empty, `memory_core` omits the application header entirely rather than transmitting a placeholder string.

Sources: [integrations/claude-code-plugin/core/_harness_id.py:6-11](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/_harness_id.py#L6-L11)

### Multi-Agent Environment Scoping and CLI Integration

Multi-agent runtimes configure telemetry initialization (see [Telemetry and Metrics](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/telemetry-ops/telemetry-and-metrics)) and CLI parameter parsing dynamically based on command-line arguments. When executing diagnostics or control commands via `memory_cli.py`, operators can supply explicit `--harness` flags to override default source tags and bind the telemetry collector to the target environment.

```python
def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--plugin-data-dir", default="")
    parser.add_argument("--harness", default="")
    subparsers = parser.add_subparsers(dest="command", required=True)

    status = subparsers.add_parser("status")
    status.add_argument("--json", action="store_true")

    doctor_parser = subparsers.add_parser("doctor")
    doctor_parser.add_argument("--json", action="store_true")

    subparsers.add_parser("pause")
    subparsers.add_parser("resume")

    forget = subparsers.add_parser("forget")
    forget.add_argument("--remote", action="store_true")
    forget.add_argument("--yes", action="store_true")
    forget.add_argument("--include-project-memory", action="store_true")

    args = parser.parse_args()
    if args.harness:
        source_tag = f"{args.harness.replace('-', '_')}_plugin"
        configure_harness(args.harness, source_tag=source_tag)
        telemetry.init(harness=args.harness, source_tag=source_tag.upper())
    if args.plugin_data_dir:
```
Sources: [integrations/claude-code-plugin/core/memory_cli.py:61-86](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/memory_cli.py#L61-L86), [integrations/mem0-agent-plugin/core/memory_cli.py:61-86](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/memory_cli.py#L61-L86)

> [!WARNING]
> Failing to pass matching harness identifiers during concurrent multi-agent executions risks cross-contamination of local evidence stores when multiple plugins share an unsegmented root directory. Always set explicit `MEM0_CODE_DATA_DIR` overrides or plugin data path flags.

Sources: [integrations/claude-code-plugin/core/memory_cli.py:86-88](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/memory_cli.py#L86-L88), [integrations/mem0-agent-plugin/core/memory_cli.py:86-88](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/memory_cli.py#L86-L88)

## Related

- [Python Agent Core](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/python-agent-core)
- [TypeScript Agent Core](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/agent-plugins/typescript-agent-core)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/llms.txt) for all pages in this wiki.
