---
title: "Python CLI Architecture"
description: "The Python CLI architecture of the Mem0 CLI provides a Typer-powered command-line interface designed for managing AI agent memory layers and platform integrations. It coordinates argument parsing, ..."
last_updated: "2026-10-11T17:37:10.214965+00:00"
canonical_url: "https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/cli-tools/python-cli-architecture"
---

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

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

- [cli/python/src/mem0_cli/app.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py)
- [integrations/openclaw/cli/commands.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/openclaw/cli/commands.ts)
- [cli/python/src/mem0_cli/backend/platform.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/platform.py)
- [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts)
- [cli/python/src/mem0_cli/commands/memory.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/memory.py)
- [cli/python/src/mem0_cli/backend/base.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/base.py)
- [integrations/mem0-agent-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/mem0-agent-plugin/core/memory_cli.py)
- [cli/python/src/mem0_cli/output.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py)
- [integrations/kimi-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/kimi-plugin/core/memory_cli.py)
- [integrations/codex-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/codex-plugin/core/memory_cli.py)
- [integrations/antigravity-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/antigravity-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/claude-code-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/claude-code-plugin/core/memory_cli.py)
- [integrations/cursor-plugin/core/memory_cli.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/cursor-plugin/core/memory_cli.py)
- [cli/python/src/mem0_cli/branding.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py)
- [cli/python/src/mem0_cli/commands/events_cmd.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/events_cmd.py)
- [cli/python/src/mem0_cli/backend/__init__.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/__init__.py)
- [cli/python/src/mem0_cli/commands/utils.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/utils.py)
- [cli/python/src/mem0_cli/commands/__init__.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/__init__.py)
- [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts)
- [scripts/oss-to-platform-migrate.sh](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/scripts/oss-to-platform-migrate.sh)
- [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts)
- [cli/node/src/backend/base.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts)
- [cli/python/src/mem0_cli/__main__.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/__main__.py)
- [cli/python/src/mem0_cli/config.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py)
- [cli/python/src/mem0_cli/commands/entities.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/entities.py)
</details>

## Overview

The Python CLI architecture of the Mem0 CLI provides a Typer-powered command-line interface designed for managing AI agent memory layers and platform integrations. It coordinates argument parsing, subcommand routing, piped input handling, and secure configuration persistence while abstracting communication through a pluggable backend layer. By supporting multiple output modes—including human-readable Rich console rendering, tabular displays, and structured JSON envelopes—the CLI serves both interactive operators and programmatic AI agents.

Sources: [cli/python/src/mem0_cli/app.py:1-32](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L1-L32), [cli/python/src/mem0_cli/config.py:1-8](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L1-L8), [cli/python/src/mem0_cli/config.py:147-150](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L147-L150), [cli/python/src/mem0_cli/output.py:207-218](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L207-L218), [cli/python/src/mem0_cli/output.py:338-342](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L338-L342)

## Entrypoint and Dispatch Architecture

### Entrypoint and Execution Dispatch

The Mem0 CLI is initialized through `cli/python/src/mem0_cli/__main__.py`, which directly invokes the `main()` function exported by the core application module. Command execution relies on Typer to manage subcommands, arguments, and global options while orchestrating execution dispatch.

```python
"""Allow running with `python -m mem0_cli`."""

from mem0_cli.app import main

main()
```
Sources: [cli/python/src/mem0_cli/__main__.py:1-5](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/__main__.py#L1-L5)

The main Typer application instance (`app`) is configured with specific formatting settings, help behaviors, and version metadata upon startup.

```python
app = typer.Typer(
    name="mem0",
    help=f"◆ Mem0 CLI v{__version__} · Python SDK\n\n   The Memory Layer for AI Agents",
    no_args_is_help=True,
    rich_markup_mode="rich",
    pretty_exceptions_enable=False,
    add_completion=False,
    subcommand_metavar="<command> [options]",
    options_metavar="",
)
```
Sources: [cli/python/src/mem0_cli/app.py:23-32](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L23-L32)

### Global Options and Argument Resolution

Global arguments and options—such as version flags and agent output formatting—are processed via the primary application callback (`main_callback`). Sub-groups for configuration (`config_app`), entity operations (`entity_app`), and event inspection (`event_app`) are defined independently and later registered onto the primary app instance to govern help menu ordering and isolate telemetry triggers.

```python
config_app = typer.Typer(
    name="config",
    help="Manage mem0 configuration.",
    no_args_is_help=True,
    rich_markup_mode="rich",
)

entity_app = typer.Typer(
    name="entity",
    help="Manage entities.",
    no_args_is_help=True,
    rich_markup_mode="rich",
)

event_app = typer.Typer(
    name="event",
    help="Inspect background processing events.",
    no_args_is_help=True,
    rich_markup_mode="rich",
)
```
Sources: [cli/python/src/mem0_cli/app.py:36-55](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L36-L55)

Entity IDs are dynamically resolved through `_resolve_ids`, which prioritizes explicit CLI arguments over configuration file defaults unless no explicit identifiers are specified.

```python
def _resolve_ids(
    config,
    *,
    user_id: str | None = None,
    agent_id: str | None = None,
    app_id: str | None = None,
    run_id: str | None = None,
):
    """Resolve entity IDs: CLI flag > config default > None.

    If any explicit ID is provided, only use explicit IDs (don't mix
    in defaults for other entity types which would over-filter).
    If no explicit IDs, fall back to all configured defaults.
    """
    has_explicit = any([user_id, agent_id, app_id, run_id])
    if has_explicit:
        return {
            "user_id": user_id or None,
            "agent_id": agent_id or None,
            "app_id": app_id or None,
            "run_id": run_id or None,
        }
    return {
        "user_id": config.defaults.user_id or None,
        "agent_id": config.defaults.agent_id or None,
        "app_id": config.defaults.app_id or None,
        "run_id": config.defaults.run_id or None,
    }
```
Sources: [cli/python/src/mem0_cli/app.py:164-191](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L164-L191)

> [!NOTE]
> When any explicit entity ID (`user_id`, `agent_id`, `app_id`, or `run_id`) is passed on the command line, `_resolve_ids` completely suppresses fallback defaults for other entity scopes to prevent unintended cross-filtering.

### Piped Input Handling

The CLI inspects stream conditions to support piping text directly into memory creation or search commands from standard input. The input handler verifies both file descriptor status and runtime execution context using `_stdin_is_piped` and `_read_stdin`.

```python
def _stdin_is_piped() -> bool:
    """Return True only when stdin is an actual pipe or file redirect — not a bare open fd."""
    from mem0_cli.state import is_agent_mode

    if is_agent_mode():
        return False
    try:
        mode = os.fstat(sys.stdin.fileno()).st_mode
        return _stat_mod.S_ISFIFO(mode) or _stat_mod.S_ISREG(mode)
    except Exception:
        return False


def _read_stdin() -> str | None:
    """Read from stdin if it is an actual pipe or file redirect (not a TTY, not agent mode)."""
    if _stdin_is_piped():
        return sys.stdin.read().strip() or None
    return None
```
Sources: [cli/python/src/mem0_cli/app.py:194-211](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L194-L211)

> [!WARNING]
> Piped input extraction via `_stdin_is_piped()` automatically returns `False` if agent mode is active (`is_agent_mode() == True`), preventing programmatic subprocess hangs when standard input is redirected by autonomous agent frameworks.

### Backend Validation and Telemetry Flow

Before dispatching commands that require network connectivity, `_get_backend_and_config` initializes the platform client, verifies API tokens against the `/v1/ping/` endpoint with a strict 5-second timeout, and tracks user identifiers for telemetry.

```python
def _get_backend_and_config(
    api_key: str | None = None,
    base_url: str | None = None,
):
    """Build and return the Platform backend plus the loaded config.

    Validates the API key upfront via ``/v1/ping/`` and caches the
    resolved user email for telemetry.
    """
    global _validated_user_email

    from mem0_cli.backend import get_backend
    from mem0_cli.backend.platform import AuthError
    from mem0_cli.config import load_config, save_config

    config = load_config()

    if api_key:
        config.platform.api_key = api_key
    if base_url:
        config.platform.base_url = base_url

    if not config.platform.api_key:
        print_error(
            err_console,
            "No API key configured.",
            hint="Run 'mem0 init' or set MEM0_API_KEY environment variable.",
        )
        raise typer.Exit(1)

    backend = get_backend(config)

    # Validate the API key upfront with a fast timeout
    try:
        ping_data = backend.ping(timeout=5.0)
        email = ping_data.get("user_email") if isinstance(ping_data, dict) else None
        if email:
            _validated_user_email = email
            if config.platform.user_email != email:
                config.platform.user_email = email
                with contextlib.suppress(Exception):
                    save_config(config)
    except AuthError:
        print_error(
            err_console,
            "Invalid or expired API key.",
            hint="Run 'mem0 init' or set MEM0_API_KEY environment variable.",
        )
        raise typer.Exit(1) from None
    except Exception:
        print_warning(err_console, "Could not validate API key (network issue). Proceeding anyway.")

    return backend, config
```
Sources: [cli/python/src/mem0_cli/app.py:100-152](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py#L100-L152)

## Configuration Model and State Management

### Configuration Precedence and Directory Structure

The Mem0 Python CLI manages persistent user options, authentication keys, default scopes, and telemetry identifiers through a hierarchical configuration store located at `~/.mem0/config.json`. Configuration values and runtime settings are resolved following a strict precedence order where higher-priority inputs override lower-priority defaults:

| Precedence | Source Layer | Examples |
| :--- | :--- | :--- |
| 1 (Highest) | CLI Flags | `--api-key`, `--base-url` |
| 2 | Environment Variables | `MEM0_API_KEY`, `MEM0_BASE_URL`, `MEM0_USER_ID`, `MEM0_AGENT_ID`, `MEM0_APP_ID`, `MEM0_RUN_ID` |
| 3 | Configuration File | `~/.mem0/config.json` |
| 4 (Lowest) | Hardcoded Defaults | `https://api.mem0.ai`, version `1`, empty strings |

Sources: [cli/python/src/mem0_cli/config.py:1-8](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L1-L8)

When the configuration directory or file is initialized or updated, `ensure_config_dir` guarantees that `~/.mem0` is created with strict file permissions (`0700`, restricting access exclusively to the file owner), while saved configuration files are explicitly secured with user-only read and write permissions (`0600`).

```python
CONFIG_DIR = Path.home() / ".mem0"
CONFIG_FILE = CONFIG_DIR / "config.json"

DEFAULT_BASE_URL = "https://api.mem0.ai"
CONFIG_VERSION = 1
```
Sources: [cli/python/src/mem0_cli/config.py:19-23](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L19-L23)

```python
def ensure_config_dir() -> Path:
    """Create ~/.mem0 directory with secure permissions if it doesn't exist."""
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    os.chmod(CONFIG_DIR, stat.S_IRWXU)  # 0700
    return CONFIG_DIR
```
Sources: [cli/python/src/mem0_cli/config.py:81-85](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L81-L85)

```python
with open(CONFIG_FILE, "w") as f:
    json.dump(data, f, indent=2)

os.chmod(CONFIG_FILE, stat.S_IRUSR | stat.S_IWUSR)  # 0600

```
Sources: [cli/python/src/mem0_cli/config.py:177-181](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L177-L181)

> [!CAUTION]
> Both `ensure_config_dir` and `save_config` execute explicit `os.chmod` calls enforcing `0700` on the `.mem0` directory and `0600` on `config.json`. Unprivileged environments or container filesystems lacking POSIX permission support may fail to restrict file modes, though configuration serialization proceeds regardless.

### Dataclass Schemas and Aliases

The underlying data model is structured around typed dataclasses that represent distinct domains: `PlatformConfig`, `DefaultsConfig`, `TelemetryConfig`, and `AgentRushConfig`, all aggregated inside `Mem0Config`. Short-form CLI configuration keys map directly to nested attributes via `SHORT_KEY_ALIASES`.

```python
@dataclass
class PlatformConfig:
    api_key: str = ""
    base_url: str = DEFAULT_BASE_URL
    user_email: str = ""
    # Agent Mode (unclaimed-shadow signup)
    agent_mode: bool = False  # True while the key is an unclaimed agent-mode key
    created_via: str = ""  # "agent_mode" | "email" | "api_key" | "existing_key"
    agent_caller: str = (
        ""  # canonical agent name when created_via == "agent_mode" (e.g. "claude-code")
    )
    claimed_at: str = ""  # ISO timestamp once the agent has been claimed by a human
    default_user_id: str = ""  # `user_<slug>` returned by bootstrap; used as auto-default


@dataclass
class DefaultsConfig:
    user_id: str = ""
    agent_id: str = ""
    app_id: str = ""
    run_id: str = ""


@dataclass
class TelemetryConfig:
    anonymous_id: str = ""


@dataclass
class AgentRushConfig:
    # ISO timestamp the human acknowledged the "memories are public" warning.
    # Empty until first interactive `mem0 agent-rush add`.
    acknowledged_at: str = ""


@dataclass
class Mem0Config:
    version: int = CONFIG_VERSION
    defaults: DefaultsConfig = field(default_factory=DefaultsConfig)
    platform: PlatformConfig = field(default_factory=PlatformConfig)
    telemetry: TelemetryConfig = field(default_factory=TelemetryConfig)
    agent_rush: AgentRushConfig = field(default_factory=AgentRushConfig)


SHORT_KEY_ALIASES: dict[str, str] = {
    "api_key": "platform.api_key",
    "base_url": "platform.base_url",
    "user_email": "platform.user_email",
    "user_id": "defaults.user_id",
    "agent_id": "defaults.agent_id",
    "app_id": "defaults.app_id",
    "run_id": "defaults.run_id",
}
```
Sources: [cli/python/src/mem0_cli/config.py:26-78](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L26-L78)

> [!NOTE]
> When `save_config` serializes active options to disk, it also invokes `plugin_sync.sync_api_key(config.platform.api_key)` as an idempotent, best-effort operation to propagate API keys into ecosystem touchpoints like shell RC files and plugin environment files, catching any `IOError` to ensure `config.json` remains the authoritative write target.

### Nested Loading and Type Coercion

Configuration loading is implemented by `load_config`, which instantiates a base `Mem0Config`, parses JSON data from disk if present, and layers environment variable overrides on top.

```python
def load_config() -> Mem0Config:
    """Load config from file, applying env var overrides."""
    config = Mem0Config()

    if CONFIG_FILE.exists():
        with open(CONFIG_FILE) as f:
            data = json.load(f)

        config.version = data.get("version", CONFIG_VERSION)

        plat = data.get("platform", {})
        config.platform.api_key = plat.get("api_key", "")
        config.platform.base_url = plat.get("base_url", DEFAULT_BASE_URL)
        config.platform.user_email = plat.get("user_email", "")
        config.platform.agent_mode = bool(plat.get("agent_mode", False))
        config.platform.created_via = plat.get("created_via", "")
        config.platform.agent_caller = plat.get("agent_caller", "")
        config.platform.claimed_at = plat.get("claimed_at", "")
        config.platform.default_user_id = plat.get("default_user_id", "")

        defaults = data.get("defaults", {})
        config.defaults.user_id = defaults.get("user_id", "")
        config.defaults.agent_id = defaults.get("agent_id", "")
        config.defaults.app_id = defaults.get("app_id", "")
        config.defaults.run_id = defaults.get("run_id", "")
        telemetry = data.get("telemetry", {})
        config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")

        agent_rush = data.get("agent_rush", {})
        config.agent_rush.acknowledged_at = agent_rush.get("acknowledged_at", "")

    # Environment variable overrides
    env_key = os.environ.get("MEM0_API_KEY")
    if env_key:
        config.platform.api_key = env_key

    env_base = os.environ.get("MEM0_BASE_URL")
    if env_base:
        config.platform.base_url = env_base

    env_user_id = os.environ.get("MEM0_USER_ID")
    if env_user_id:
        config.defaults.user_id = env_user_id

    env_agent_id = os.environ.get("MEM0_AGENT_ID")
    if env_agent_id:
        config.defaults.agent_id = env_agent_id

    env_app_id = os.environ.get("MEM0_APP_ID")
    if env_app_id:
        config.defaults.app_id = env_app_id

    env_run_id = os.environ.get("MEM0_RUN_ID")
    if env_run_id:
        config.defaults.run_id = env_run_id

    return config
```
Sources: [cli/python/src/mem0_cli/config.py:88-144](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L88-L144)

Property getters and setters (`get_nested_value` and `set_nested_value`) support dotted path strings (such as `platform.api_key` or `defaults.user_id`) along with short aliases. The setter performs automatic type coercion based on the existing attribute type, converting boolean representations and integers safely.

```python
def get_nested_value(config: Mem0Config, dotted_key: str) -> Any:
    """Get a config value by dotted path, e.g. 'platform.api_key' or short form 'api_key'."""
    dotted_key = SHORT_KEY_ALIASES.get(dotted_key, dotted_key)
    parts = dotted_key.split(".")
    obj: Any = config
    for part in parts:
        if hasattr(obj, part):
            obj = getattr(obj, part)
        else:
            return None
    return obj


def set_nested_value(config: Mem0Config, dotted_key: str, value: str) -> bool:
    """Set a config value by dotted path. Returns True on success."""
    dotted_key = SHORT_KEY_ALIASES.get(dotted_key, dotted_key)
    parts = dotted_key.split(".")
    obj: Any = config
    for part in parts[:-1]:
        if hasattr(obj, part):
            obj = getattr(obj, part)
        else:
            return False

    final_key = parts[-1]
    if not hasattr(obj, final_key):
        return False

    current = getattr(obj, final_key)
    # Type coercion
    if isinstance(current, bool):
        value = value.lower() in ("true", "1", "yes")  # type: ignore[assignment]
    elif isinstance(current, int):
        try:
            value = int(value)  # type: ignore[assignment]
        except ValueError:
            return False

    setattr(obj, final_key, value)
    return True
```
Sources: [cli/python/src/mem0_cli/config.py:205-244](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/config.py#L205-L244)

## Backend Abstraction and Factory Selection

### Abstract Interface Definition

The `Backend` abstract base class, defined in `cli/python/src/mem0_cli/backend/base.py`, establishes the core contract that any storage or platform backend must fulfill. It inherits from `ABC` and declares eleven abstract methods covering memory creation, semantic and keyword search, record retrieval, paginated listing, updates, deletion, entity management, status checks, and event inspection.

```python
class Backend(ABC):
    """Abstract interface for mem0 backends."""

    @abstractmethod
    def add(
        self,
        content: str | None = None,
        messages: list[dict] | None = None,
        *,
        user_id: str | None = None,
        agent_id: str | None = None,
        app_id: str | None = None,
        run_id: str | None = None,
        metadata: dict | None = None,
        immutable: bool = False,
        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,
    ) -> dict: ...

    @abstractmethod
    def search(
        self,
        query: str,
        *,
        user_id: str | None = None,
        agent_id: str | None = None,
        app_id: str | None = None,
        run_id: str | None = None,
        top_k: int = 10,
        threshold: float = 0.3,
        rerank: bool = False,
        keyword: bool = False,
        filters: dict | None = None,
        fields: list[str] | None = None,
        show_expired: bool = False,
        reference_date: str | None = None,
        latest_only: bool = False,
    ) -> list[dict]: ...

    @abstractmethod
    def get(self, memory_id: str) -> dict: ...

    @abstractmethod
    def list_memories(
        self,
        *,
        user_id: str | None = None,
        agent_id: str | None = None,
        app_id: str | None = None,
        run_id: str | None = None,
        page: int = 1,
        page_size: int = 100,
        category: str | None = None,
        after: str | None = None,
        before: str | None = None,
        show_expired: bool = False,
        latest_only: bool = False,
    ) -> list[dict]: ...

    @abstractmethod
    def update(
        self,
        memory_id: str,
        content: str | None = None,
        metadata: dict | None = None,
        *,
        expiration_date: str | None = None,
        timestamp: int | None = None,
    ) -> dict: ...

    @abstractmethod
    def delete(
        self,
        memory_id: str | None = None,
        *,
```
Sources: [cli/python/src/mem0_cli/backend/base.py:11-90](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/base.py#L11-L90)

Every method enforces explicit keyword arguments and positional scopes such as `user_id`, `agent_id`, `app_id`, and `run_id`. The contract ensures uniform method signatures across different backend targets.

| Abstract Method | Return Type | Key Parameters |
| :--- | :--- | :--- |
| `add` | `dict` | `content`, `messages`, `user_id`, `agent_id`, `app_id`, `run_id`, `metadata`, `immutable`, `infer`, `expires`, `custom_instructions`, `agent_custom_instructions`, `custom_categories`, `structured_data_schema`, `timestamp` |
| `search` | `list[dict]` | `query`, `top_k`, `threshold`, `rerank`, `keyword`, `filters`, `fields`, `show_expired`, `reference_date`, `latest_only` |
| `get` | `dict` | `memory_id` |
| `list_memories` | `list[dict]` | `page`, `page_size`, `category`, `after`, `before`, `show_expired`, `latest_only` |
| `update` | `dict` | `memory_id`, `content`, `metadata`, `expiration_date`, `timestamp` |
| `delete` | `dict` | `memory_id`, `all`, `delete_linked` |
| `delete_entities` | `dict` | `user_id`, `agent_id`, `app_id`, `run_id` |
| `status` | `dict[str, Any]` | `user_id`, `agent_id` |
| `entities` | `list[dict]` | `entity_type` |
| `list_events` | `list[dict]` | *(none)* |
| `get_event` | `dict` | `event_id` |

Sources: [cli/python/src/mem0_cli/backend/base.py:15-124](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/base.py#L15-L124)

> [!NOTE]
> The abstract interface does not prescribe storage or serialization details; it defines pure method boundaries so that command handlers interact with memory collections without knowing whether data resides locally or on a remote SaaS cluster.

### Platform Backend Instantiation and Lifecycle

The `PlatformBackend` concrete class implements the `Backend` interface by communicating directly with the Mem0 Platform API (`api.mem0.ai`). Its constructor accepts a `PlatformConfig` instance, strips trailing slashes from `base_url`, and configures a persistent `httpx.Client` instance with request headers.

```python
class PlatformBackend(Backend):
    """Backend that talks to the mem0 Platform API."""

    def __init__(self, config: PlatformConfig) -> None:
        self.config = config
        self.base_url = config.base_url.rstrip("/")
        self._client = httpx.Client(
            base_url=self.base_url,
            headers={
                "Authorization": f"Token {config.api_key}",
                "Content-Type": "application/json",
                "X-Mem0-Source": "CLI",
                "X-Mem0-Client": f"mem0-cli-python/{__version__}",
                "X-Mem0-Client-Language": "python",
                "X-Mem0-Client-Version": __version__,
            },
            timeout=30.0,
        )
```
Sources: [cli/python/src/mem0_cli/backend/platform.py:19-36](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/platform.py#L19-L36)

The HTTP client injects authentication and telemetry headers into every outbound request:

| Header Name | Value / Format |
| :--- | :--- |
| `Authorization` | `Token {config.api_key}` |
| `Content-Type` | `application/json` |
| `X-Mem0-Source` | `CLI` |
| `X-Mem0-Client` | `mem0-cli-python/{__version__}` |
| `X-Mem0-Client-Language` | `python` |
| `X-Mem0-Client-Version` | `__version__` |

Sources: [cli/python/src/mem0_cli/backend/platform.py:27-34](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/platform.py#L27-L34)

The client enforces a default timeout of `30.0` seconds. Path segments are encoded using `_encode_path_segment`, which wraps `urllib.parse.quote` with `safe=""` to prevent path traversal or malformed URL injection.

```python
def _encode_path_segment(value: Any) -> str:
    return quote(str(value), safe="")
```
Sources: [cli/python/src/mem0_cli/backend/platform.py:15-16](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/platform.py#L15-L16)

### Factory Dispatch

Backend creation is centralized in the `get_backend` factory function. It accepts a `Mem0Config` instance and instantiates `PlatformBackend` using `config.platform`.

```python
def get_backend(config: Mem0Config) -> Backend:
    """Return the Platform backend."""
    from mem0_cli.backend.platform import PlatformBackend

```
Sources: [cli/python/src/mem0_cli/backend/base.py:127-130](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/backend/base.py#L127-L130)

> [!TIP]
> `get_backend` performs a local import of `PlatformBackend` inside the function body rather than at the module level. This lazy import prevents circular dependencies between configuration modules, state managers, and platform client definitions during CLI startup.

## Memory Command Workflows and Execution

### Memory Operations and Execution Flows

The memory command layer handles user requests by validating input parameters, invoking backend methods within timed status contexts, and formatting responses based on terminal flags or autonomous agent mode. Memory creation, search, retrieval, listing, import, and background event inspection are orchestrated through dedicated command handlers.

When searching memories using `cmd_search`, the CLI validates `--top-k` against a minimum value of `1` and ensures `--threshold` falls within the inclusive range `0.0` to `1.0`. Any supplied filter JSON is parsed via `json.loads` before invoking `backend.search`. Similarly, `cmd_list` enforces boundary checks on `page` and `page_size` parameters prior to calling `backend.list_memories`.

```python
if top_k < 1:
    print_error(err_console, "--top-k must be >= 1.")
    raise typer.Exit(1)
if not (0.0 <= threshold <= 1.0):
    print_error(err_console, "--threshold must be between 0.0 and 1.0.")
    raise typer.Exit(1)

```
Sources: [cli/python/src/mem0_cli/commands/memory.py:277-283](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/memory.py#L277-L283)

> [!WARNING]
> Failing to provide valid JSON to `--filter` during a search or passing non-positive integer values to pagination flags results in an immediate termination via `typer.Exit(1)` after writing an error description to the standard error console.

### Execution Call Chains and Agent Envelopes

Command execution pipelines leverage shared formatting functions when operating under `--agent` mode or structured JSON output. For list and search operations, raw backend records pass through envelope generation and field projection before rendering.

The execution call chain for listing memories proceeds as follows:
1. `cmd_list` invokes `backend.list_memories` and receives raw records.
2. `format_agent_envelope` wraps the command name, duration, scope filters, and data.
3. `sanitize_agent_data` processes the command category and project dataset items.
4. `pick` filters dictionary keys down to the minimal required subset.

```python
results = backend.list_memories(
    user_id=user_id,
    agent_id=agent_id,
    app_id=app_id,
    run_id=run_id,
    page=page,
    page_size=page_size,
    category=category,
    after=after,
    before=before,
    show_expired=show_expired,
    latest_only=latest_only,
)
…
def sanitize_agent_data(command: str, data: Any) -> Any:
    """Project API response data to minimal relevant fields for agent consumption."""

    def pick(obj: dict, keys: list) -> dict:
        return {k: obj[k] for k in keys if k in obj}

    if data is None:
        return data

    if command == "add":
        items = data if isinstance(data, list) else [data]
        result = []
        for item in items:
            if item.get("status") == "PENDING":
                result.append(pick(item, ["status", "event_id"]))
            else:
                result.append(pick(item, ["id", "memory", "event"]))
        return result

    if command == "search":
        return [
            pick(r, ["id", "memory", "score", "created_at", "categories", "expiration_date"])
            for r in data
        ]

    if command == "list":
        return [
            pick(r, ["id", "memory", "created_at", "categories", "expiration_date"]) for r in data
        ]

```
Sources: [cli/python/src/mem0_cli/commands/memory.py:408-420](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/memory.py#L408-L420), [cli/python/src/mem0_cli/output.py:245-274](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L245-L274), [cli/python/src/mem0_cli/output.py:329-361](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L329-L361)

Similarly, the execution call chain for searching memories proceeds as:
1. `cmd_search` queries the backend and measures execution time via `_time.perf_counter()`.
2. `format_agent_envelope` constructs a JSON envelope containing execution duration and scope parameters.
3. `sanitize_agent_data` matches the `search` command type.
4. `pick` extracts only `id`, `memory`, `score`, `created_at`, `categories`, and `expiration_date` fields from each result object.

```python
results = backend.search(
    query,
    user_id=user_id,
    agent_id=agent_id,
    app_id=app_id,
    run_id=run_id,
    top_k=top_k,
    threshold=threshold,
    rerank=rerank,
    keyword=keyword,
    filters=filters,
    fields=field_list,
    show_expired=show_expired,
    reference_date=reference_date,
    latest_only=latest_only,
)
…
def format_agent_envelope(
    console: Console,
    *,
    command: str,
    data: Any,
    duration_ms: int | None = None,
    scope: dict | None = None,
    count: int | None = None,
) -> None:
    """Output structured JSON envelope for agent/programmatic use (--json/--agent mode)."""
    envelope: dict[str, Any] = {
        "status": "success",
        "command": command,
    }
    if duration_ms is not None:
        envelope["duration_ms"] = duration_ms
    if scope:
        filtered = {k: v for k, v in scope.items() if v}
        if filtered:
            envelope["scope"] = filtered
    if count is not None:
        envelope["count"] = count
    envelope["data"] = sanitize_agent_data(command, data)

    # Surface the unclaimed-Agent-Mode notice (if any) in the envelope so an
    # agent reading the JSON output sees it without inspecting HTTP headers.
    from mem0_cli.state import take_notice

    notice = take_notice()
    if notice:
        envelope["mem0_notice"] = notice

    console.print_json(json.dumps(envelope, default=str))
…
def sanitize_agent_data(command: str, data: Any) -> Any:
    """Project API response data to minimal relevant fields for agent consumption."""

    def pick(obj: dict, keys: list) -> dict:
        return {k: obj[k] for k in keys if k in obj}

    if data is None:
        return data

    if command == "add":
        items = data if isinstance(data, list) else [data]
        result = []
        for item in items:
            if item.get("status") == "PENDING":
                result.append(pick(item, ["status", "event_id"]))
            else:
                result.append(pick(item, ["id", "memory", "event"]))
        return result

    if command == "search":
        return [
            pick(r, ["id", "memory", "score", "created_at", "categories", "expiration_date"])
            for r in data
        ]
```
Sources: [cli/python/src/mem0_cli/commands/memory.py:287-302](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/memory.py#L287-L302), [cli/python/src/mem0_cli/output.py:245-268](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L245-L268), [cli/python/src/mem0_cli/output.py:329-361](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L329-L361)

```mermaid
sequenceDiagram
    participant memory.py as memory.py
    participant output.py as output.py
    memory.py->>output.py: format_agent_envelope()
    output.py->>output.py: sanitize_agent_data()
    output.py->>output.py: pick()
```
Sources: [cli/python/src/mem0_cli/commands/memory.py:408-420](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/memory.py#L408-L420), [cli/python/src/mem0_cli/output.py:245-361](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L245-L361)

### Background Event Inspection and Status Mapping

Asynchronous processing workflows on the platform generate background events that can be inspected via event commands. The `events_cmd` module maps event states to rich terminal styles and formats detailed execution summaries.

```python
_STATUS_STYLE = {
    "SUCCEEDED": f"[{SUCCESS_COLOR}]SUCCEEDED[/]",
    "PENDING": f"[{ACCENT_COLOR}]PENDING[/]",
    "FAILED": f"[{ERROR_COLOR}]FAILED[/]",
    "PROCESSING": f"[{WARNING_COLOR}]PROCESSING[/]",
}
```
Sources: [cli/python/src/mem0_cli/commands/events_cmd.py:26-31](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/events_cmd.py#L26-L31)

| Status Constant | Console Style / Color Mapping |
| :--- | :--- |
| `SUCCEEDED` | `[{SUCCESS_COLOR}]SUCCEEDED[/]` |
| `PENDING` | `[{ACCENT_COLOR}]PENDING[/]` |
| `FAILED` | `[{ERROR_COLOR}]FAILED[/]` |
| `PROCESSING` | `[{WARNING_COLOR}]PROCESSING[/]` |

Sources: [cli/python/src/mem0_cli/commands/events_cmd.py:26-31](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/events_cmd.py#L26-L31)

When executing `cmd_event_status`, backend event details are retrieved and formatted into a Rich panel containing metadata, latency figures, creation and update timestamps, and nested result items.

```python
with timed_status(err_console, "Fetching event...") as _ts:
    try:
        ev = backend.get_event(event_id)
…
panel = Panel(
    content,
    title=f"[{BRAND_COLOR}]Event Status[/]",
    title_align="left",
    border_style=BRAND_COLOR,
    padding=(1, 1),
)
console.print()
console.print(panel)
```
Sources: [cli/python/src/mem0_cli/commands/events_cmd.py:114-116](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/events_cmd.py#L114-L116), [cli/python/src/mem0_cli/commands/events_cmd.py:167-175](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/events_cmd.py#L167-L175)

> [!TIP]
> When background memory ingestion returns `PENDING` status entries from the platform API, the output formatter automatically deduplicates events sharing the same `event_id` and prompts the user with status checking instructions.

## Multi-Format Output and Terminal Rendering

### Terminal Styling and Branding

The CLI utilizes the Rich library to render decorative console components, ASCII banners, and styled text blocks. Color palettes are centrally defined in the branding module to maintain visual consistency across interactive shells.

```python
BRAND_COLOR = "#8b5cf6"  # Purple
ACCENT_COLOR = "#a78bfa"
SUCCESS_COLOR = "#22c55e"
ERROR_COLOR = "#ef4444"
WARNING_COLOR = "#f59e0b"
DIM_COLOR = "#6b7280"
```
Sources: [cli/python/src/mem0_cli/branding.py:29-34](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py#L29-L34)

| Color Constant | Hex Value | Semantic Purpose |
| :--- | :--- | :--- |
| `BRAND_COLOR` | `#8b5cf6` | Primary purple branding, welcome panel borders, and info symbols |
| `ACCENT_COLOR` | `#a78bfa` | Secondary highlights, updated state icons, and table headers |
| `SUCCESS_COLOR` | `#22c55e` | Success indicators, added memory plus icons |
| `ERROR_COLOR` | `#ef4444` | Error messages and deleted memory minus symbols |
| `WARNING_COLOR` | `#f59e0b` | Warning indicators and processing states |
| `DIM_COLOR` | `#6b7280` | Muted text, timestamps, scopes, and no-change symbols |

Sources: [cli/python/src/mem0_cli/branding.py:29-34](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py#L29-L34)

ASCII symbols adapt dynamically based on terminal capabilities and environment flags. The helper function `_sym` evaluates whether `sys.stdout.isatty()` is true and ensures `NO_COLOR` is absent from environment variables before returning rich Unicode glyphs; otherwise, it falls back to plain ASCII text equivalents.

```python
def _sym(fancy: str, plain: str) -> str:
    """Return *fancy* when stdout is a TTY with colour, else *plain*."""
    if not sys.stdout.isatty() or os.environ.get("NO_COLOR") is not None:
        return plain
    return fancy
```
Sources: [cli/python/src/mem0_cli/branding.py:37-41](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py#L37-L41)

Welcome banners, constructed using a multi-line ASCII logo and a Python SDK version subtitle fetched via `_get_version()`, are suppressed entirely when agent mode is active.

```python
from mem0_cli.state import is_agent_mode

if is_agent_mode():
    return
logo_text = Text(LOGO, style=f"bold {BRAND_COLOR}")
tagline = Text(f"  {TAGLINE}\n", style=f"{ACCENT_COLOR}")

content = Text()
content.append_text(logo_text)
content.append_text(tagline)

panel = Panel(
    content,
    border_style=BRAND_COLOR,
    padding=(0, 2),
    subtitle=f"[{DIM_COLOR}]Python SDK · v{_get_version()}[/]",
    subtitle_align="right",
)
console.print(panel)
```
Sources: [cli/python/src/mem0_cli/branding.py:46-64](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py#L46-L64)

> [!NOTE]
> The `timed_status` context manager directs all spinner animations and execution timing messages to standard error (`_err = Console(stderr=True)`) rather than standard output. This guarantees that background activity indicators never contaminate machine-readable JSON or agent data streams.

Sources: [cli/python/src/mem0_cli/branding.py:14-124](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/branding.py#L14-L124)

### Agent Envelope Sanitation Call Chain

When formatting outputs for programmatic consumers or AI agent workflows, data structures pass through strict projection functions to filter out extraneous database fields. The entity listing workflow follows a precise execution chain.

1. `cmd_entities_list` invokes the backend to retrieve raw entity records and captures performance metrics via `_time.perf_counter()`.
2. `format_agent_envelope` wraps the resulting dataset inside a structured dictionary containing command metadata, counts, execution duration, and active scopes.
3. `sanitize_agent_data` inspects the command string (`entity list`) and iterates over records to project them.
4. `pick` extracts only the authorized keys (`type`, `count`, plus normalized `name` or `id`) for each item.

```python
def cmd_entities_list(backend: Backend, entity_type: str, *, output: str) -> None:
    """List entities of a given type."""
    from mem0_cli.state import is_agent_mode, set_current_command

    set_current_command("entity list")
    if is_agent_mode():
        output = "agent"
    valid_types = {"users", "agents", "apps", "runs"}
    if entity_type not in valid_types:
        print_error(
            err_console, f"Invalid entity type: {entity_type}. Use: {', '.join(valid_types)}"
        )
        raise typer.Exit(1)

    _start = _time.perf_counter()
    with timed_status(err_console, f"Fetching {entity_type}...") as _ts:
        try:
            results = backend.entities(entity_type)
        except Exception as e:
            print_error(err_console, str(e), hint="This feature may require the mem0 Platform.")
            raise typer.Exit(1) from None
    _elapsed = _time.perf_counter() - _start

    if output == "agent":
        format_agent_envelope(
            console,
            command="entity list",
            data=results,
            count=len(results),
            duration_ms=int(_elapsed * 1000),
        )
        return
…
def format_agent_envelope(
    console: Console,
    *,
    command: str,
    data: Any,
    duration_ms: int | None = None,
    scope: dict | None = None,
    count: int | None = None,
) -> None:
    """Output structured JSON envelope for agent/programmatic use (--json/--agent mode)."""
    envelope: dict[str, Any] = {
        "status": "success",
        "command": command,
    }
    if duration_ms is not None:
        envelope["duration_ms"] = duration_ms
    if scope:
        filtered = {k: v for k, v in scope.items() if v}
        if filtered:
            envelope["scope"] = filtered
    if count is not None:
        envelope["count"] = count
    envelope["data"] = sanitize_agent_data(command, data)

    # Surface the unclaimed-Agent-Mode notice (if any) in the envelope so an
    # agent reading the JSON output sees it without inspecting HTTP headers.
    from mem0_cli.state import take_notice

    notice = take_notice()
    if notice:
        envelope["mem0_notice"] = notice

    console.print_json(json.dumps(envelope, default=str))
…
def sanitize_agent_data(command: str, data: Any) -> Any:
    """Project API response data to minimal relevant fields for agent consumption."""

    def pick(obj: dict, keys: list) -> dict:
        return {k: obj[k] for k in keys if k in obj}

    if data is None:
        return data

    if command == "add":
        items = data if isinstance(data, list) else [data]
        result = []
        for item in items:
```
Sources: [cli/python/src/mem0_cli/commands/entities.py:27-58](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/entities.py#L27-L58), [cli/python/src/mem0_cli/output.py:245-301](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L245-L301), [cli/python/src/mem0_cli/output.py:329-361](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L329-L361)

```mermaid
sequenceDiagram
    participant entities.py as entities.py
    participant output.py as output.py
    entities.py->>output.py: format_agent_envelope()
    output.py->>output.py: sanitize_agent_data()
    output.py->>output.py: pick()
```
Sources: [cli/python/src/mem0_cli/commands/entities.py:27-58](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/commands/entities.py#L27-L58), [cli/python/src/mem0_cli/output.py:245-361](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L245-L361)

> [!WARNING]
> If an unclaimed Agent Mode account triggers a platform notice during execution, both `format_json_envelope` and `format_agent_envelope` retrieve it via `take_notice()` and inject it directly into the `mem0_notice` JSON key. Consuming agents must inspect this field to discover authentication states without parsing HTTP headers.

Sources: [cli/python/src/mem0_cli/output.py:233-242](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L233-L242), [cli/python/src/mem0_cli/output.py:353-360](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/output.py#L353-L360)

## Related

- [Node.js CLI Architecture](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/cli-tools/node-js-cli-architecture)
- [Agent Account Provisioning](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/cli-tools/agent-account-provisioning)


## Sitemap

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