---
title: "Node.js CLI Architecture"
description: "The Node.js CLI architecture provides the primary command-line interface for interacting with Mem0 memory layers, offering robust command routing, configuration persistence, and platform communicat..."
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/node-js-cli-architecture"
---

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

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

- [integrations/openclaw/cli/commands.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/openclaw/cli/commands.ts)
- [cli/node/src/commands/agent-mode.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/agent-mode.ts)
- [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts)
- [cli/node/src/commands/init.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/init.ts)
- [integrations/hermes-plugin-mem0/__init__.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/hermes-plugin-mem0/__init__.py)
- [integrations/hermes-plugin-mem0/_backend.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/hermes-plugin-mem0/_backend.py)
- [cli/node/src/backend/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/index.ts)
- [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts)
- [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts)
- [cli/python/src/mem0_cli/app.py](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/python/src/mem0_cli/app.py)
- [cli/node/src/commands/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/config.ts)
- [cli/node/src/backend/base.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts)
- [integrations/openclaw/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/integrations/openclaw/index.ts)
- [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts)
- [scripts/oss-to-platform-migrate.sh](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/scripts/oss-to-platform-migrate.sh)
- [cli/node/tsconfig.json](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/tsconfig.json)
- [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts)
- [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts)
- [cli/node/src/branding.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/branding.ts)
</details>

## Overview

The Node.js CLI architecture provides the primary command-line interface for interacting with Mem0 memory layers, offering robust command routing, configuration persistence, and platform communication tailored for both human operators and autonomous agents. Built around a Commander-based command dispatcher, the CLI maps subcommands to core memory operations while managing option normalization and execution flow. Sources: [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L10-L26), [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L149-L173)

State management and disk-backed configuration handle setting resolution and persistent storage across user sessions. Through an abstract backend layer and platform client implementation, the CLI connects seamlessly with SaaS endpoints, ensuring secure communication and robust error handling. Sources: [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L11-L18), [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L25-L39)

## Command Dispatch and Argument Parsing

### Entry Point and Program Initialization

The CLI executable initializes as a standard Node.js script using the Commander library to configure the root program [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L1-L26). The root `Command` instance defines global application properties, sets up positional option parsing via `.enablePositionalOptions()`, and configures help formatting [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L149-L173). Positional option configuration ensures that flags supplied after a subcommand name correctly target that subcommand rather than being intercepted at the global level [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L154-L158).

Global options registered on the root program include version inspection, output formatting overrides, and agent mode flags [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L159-L168).

| Option Flag | Description |
| :--- | :--- |
| `--version` | Show CLI version and exit |
| `--json` | Output results as JSON for programmatic use |
| `--agent` | Output as JSON (alias for `--json`, or agent bootstrap on `init`) |
| `--help` | Show help message and exit |

Sources: [cli/node/src/index.ts:159-171](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L159-L171)

> [!WARNING]
> When using the `--agent` flag with the `init` command, it serves as the unattended Agent Mode bootstrap selector rather than an output format modifier, overriding normal interactive email workflows. Sources: [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L165-L168), [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L219-L223)

### Telemetry Hooks and State Management

Execution flow across all subcommands is intercepted by a `preAction` hook attached to the root program [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L176-L204). This hook resolves the active subcommand path—combining parent and child names such as `event.list` or falling back to standalone commands—and stores it in the transient execution state [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L178-L187), [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L20-L26). Stashing the active command name ensures that JSON error envelopes include accurate command attribution [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L184-L187).

```typescript
program.hook("preAction", (_thisCommand, actionCommand) => {
	try {
		const commandName = actionCommand.name();
		const parentName = actionCommand.parent?.name();
		const fullCommand =
			parentName && parentName !== "mem0"
				? `${parentName}.${commandName}`
				: commandName;
		// Stash the active command name in shared state so the JSON
		// error envelope (printError) can report which command failed
		// instead of an empty `"command": ""` field.
		setCurrentCommand(fullCommand);
		// init fires its own telemetry from runInit with full M1-M6 props
		// (mode/agent_caller/signup_source/claimed_agent_mode); skip the
		// auto-fire here so we don't double-count.
		if (fullCommand === "init") return;
		const isAgent = !!(program.opts().json || program.opts().agent);
		captureEvent(
			`cli.${fullCommand}`,
			{
				command: fullCommand,
				is_agent: isAgent,
			},
			_validatedUserEmail,
		);
	} catch {
		/* silently swallow */
	}
});
```
Sources: [cli/node/src/index.ts:176-204](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L176-L204)

> [!NOTE]
> The `init` command skips automatic telemetry emission inside the pre-action hook because `runInit` dispatches its own telemetry payload containing comprehensive mode, caller, and signup attributes [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L189-L192). Sources: [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L189-L192)

### Option Normalization and Entity Resolution

Subcommands process user input by validating authentication credentials and normalizing filtering options [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L34-L89). Helper routines like `checkAgentMode()` inspect root options to determine if output formatting should default to agent JSON structures [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L102-L107), [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L12-L18). 

Furthermore, entity scoping relies on `resolveIds()`, which inspects explicit CLI options (`userId`, `agentId`, `appId`, `runId`). If any explicit identifier is supplied, default configuration values are omitted to prevent unwanted cross-filtering; otherwise, configured default identifiers are applied [cli/node/src/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L110-L145).

```typescript
 * Resolve entity IDs: CLI flag > config default > undefined.
 *
 * 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.
 */
function resolveIds(
	config: Mem0Config,
	opts: {
		userId?: string;
		agentId?: string;
		appId?: string;
		runId?: string;
	},
): { userId?: string; agentId?: string; appId?: string; runId?: string } {
	const hasExplicit = !!(
		opts.userId ||
		opts.agentId ||
		opts.appId ||
		opts.runId
	);
	if (hasExplicit) {
		return {
			userId: opts.userId || undefined,
			agentId: opts.agentId || undefined,
			appId: opts.appId || undefined,
			runId: opts.runId || undefined,
		};
	}
	return {
		userId: config.defaults.userId || undefined,
		agentId: config.defaults.agentId || undefined,
		appId: config.defaults.appId || undefined,
		runId: config.defaults.runId || undefined,
	};
}
```
Sources: [cli/node/src/index.ts:110-145](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/index.ts#L110-L145)

## Configuration Persistence and State Management

### Configuration Precedence and Storage Mechanics

The configuration subsystem manages disk-backed settings stored in `~/.mem0/config.json` with strict file permissions (`0o700` for the parent directory and `0o600` for the configuration file) [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L15-L16), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L85-L86), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L163-L164). Values are resolved according to a defined precedence order, where highest priority settings override lower levels [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L4-L9).

| Precedence Order | Source Layer | Description |
| :--- | :--- | :--- |
| 1 (Highest) | CLI Flags | Direct execution flags such as `--api-key` and `--base-url` [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L5) |
| 2 | Environment Variables | Runtime overrides like `MEM0_API_KEY`, `MEM0_BASE_URL`, and scoping keys [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L6), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L121-L130) |
| 3 | Configuration File | Persistent storage parsed from JSON on disk [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L7), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L93-L95) |
| 4 (Lowest) | Defaults | Built-in fallback constants including `DEFAULT_BASE_URL` (`https://api.mem0.ai`) and empty default strings [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L8), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L17), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L57-L83) |

Sources: [cli/node/src/config.ts:4-132](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L4-L132)

> [!WARNING]
> When `saveConfig` persists settings to disk, it executes an idempotent ecosystem synchronization step (`syncApiKey`) to propagate the platform API key into agent integration environments and shell configuration files, wrapping failures in a try-catch block so that disk writes remain completely unblocked [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L166-L179). Sources: [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L166-L179)

### Key Mapping and Mutation Commands

Configuration paths support dotted string lookups and short-form aliases via a static `KEY_MAP` structure [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L187-L204). Functions such as `getNestedValue` and `setNestedValue` translate these keys into internal typed properties across `platform`, `defaults`, `telemetry`, and `agentRush` sections [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L49-L55), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L206-L231). The `cmdConfigSet` routine validates the requested key, mutates the active configuration object with type-aware casting for booleans and numbers, and invokes `saveConfig` alongside success or agent envelope reporting [cli/node/src/commands/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/config.ts#L92-L108), [cli/node/src/config.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L223-L230).

```typescript
export function cmdConfigGet(key: string): void {
	setCurrentCommand("config get");
	const config = loadConfig();
	const value = getNestedValue(config, key);

	if (value === undefined) {
		printError(`Unknown config key: ${key}`);
	} else {
		// Redact secrets
		const displayValue =
			key.includes("api_key") || key.split(".").pop() === "key"
				? redactKey(String(value))
				: String(value);
		if (isAgentMode()) {
			formatAgentEnvelope({
				command: "config get",
				data: { key, value: displayValue },
			});
		} else {
			console.log(displayValue);
		}
	}
}

export function cmdConfigSet(key: string, value: string): void {
	setCurrentCommand("config set");
	const config = loadConfig();
	if (setNestedValue(config, key, value)) {
		saveConfig(config);
		const display = key.includes("key") ? redactKey(value) : value;
		if (isAgentMode()) {
			formatAgentEnvelope({
				command: "config set",
				data: { key, value: display },
			});
		} else {
			printSuccess(`${key} = ${display}`);
		}
	} else {
		printError(`Unknown config key: ${key}`);
	}
}
```
Sources: [cli/node/src/commands/config.ts:68-109](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/config.ts#L68-L109), [cli/node/src/config.ts:187-232](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/config.ts#L187-L232)

### Transient Execution State

In parallel with disk persistence, transient runtime state is maintained across command lifecycles [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L1-L53). The state module tracks whether agent mode is active (`_agentMode`), records the currently executing command identifier (`_currentCommand`), and stashes backend notices such as unclaimed agent mode reminders via `captureNotice` and `takeNotice` [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L8-L42). Furthermore, `stdinIsPiped` inspects standard input via `fs.fstatSync(0)` to detect active FIFO pipes or file redirections, automatically bypassing pipe checks whenever agent mode is enabled [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L44-L53).

```typescript
let _agentMode = false;
let _currentCommand = "";
let _pendingNotice = "";

export function isAgentMode(): boolean {
	return _agentMode;
}

export function setAgentMode(val: boolean): void {
	_agentMode = val;
}

export function getCurrentCommand(): string {
	return _currentCommand;
}

export function setCurrentCommand(name: string): void {
	_currentCommand = name;
}

/**
 * Stash a Mem0 backend notice (Agent Mode unclaimed reminder) for end-of-
 * command surfacing. Called from the platform backend after each response so
 * the notice prints once per command regardless of how many sub-requests
 * fired. Last-write-wins is fine — the message text is identical.
 */
export function captureNotice(notice: string | null | undefined): void {
	if (notice) _pendingNotice = notice;
}

export function takeNotice(): string {
	const msg = _pendingNotice;
	_pendingNotice = "";
	return msg;
}
```
Sources: [cli/node/src/state.ts:8-42](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L8-L42)

## Backend Abstraction and Platform Client

### Pluggable Interface and Instantiation Factory

The Node.js CLI defines memory backend interactions through the TypeScript `Backend` interface, establishing a standard contract for all CRUD operations, searches, entity management, and event listing [cli/node/src/backend/base.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts#L75-L116). The `getBackend` factory function accepts a global `Mem0Config` object and instantiates and returns the active SaaS platform client via `PlatformBackend` initialized with `config.platform` [cli/node/src/backend/base.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts#L141-L143), [cli/node/src/backend/index.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/index.ts#L5).

| Error Class | Status Code / Condition | Default Error Message |
| :--- | :--- | :--- |
| `AuthError` | `401` Unauthorized | `Authentication failed. Your API key may be invalid or expired.` |
| `NotFoundError` | `404` Not Found | `Resource not found: ${path}` |
| `APIError` | `400` Bad Request | `Bad request to ${path}: ${detail}` |

```typescript
export class AuthError extends Error {
	constructor(
		message = "Authentication failed. Your API key may be invalid or expired.",
	) {
		super(message);
		this.name = "AuthError";
	}
}

export class NotFoundError extends Error {
	constructor(path: string) {
		super(`Resource not found: ${path}`);
		this.name = "NotFoundError";
	}
}

export class APIError extends Error {
	constructor(path: string, detail: string) {
		super(`Bad request to ${path}: ${detail}`);
		this.name = "APIError";
	}
}
```
Sources: [cli/node/src/backend/base.ts:118-139](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts#L118-L139)

> [!NOTE]
> The `PlatformBackend` class explicitly normalizes configured base URLs by stripping trailing slashes with `config.baseUrl.replace(/\/+$/, "")` to guarantee uniform path resolution when constructing REST requests [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L29-L30). Sources: [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L29-L30)

### SaaS REST API Communication

The `PlatformBackend` class communicates directly with the Mem0 SaaS platform (`api.mem0.ai`) [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L2-L25). Every HTTP request builds standard diagnostic and authentication headers using the active API key and CLI version metadata [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L31-L39).

```typescript
this.headers = {
	Authorization: `Token ${config.apiKey}`,
	"Content-Type": "application/json",
	"X-Mem0-Source": "CLI",
	"X-Mem0-Client": `mem0-cli-node/${CLI_VERSION}`,
	"X-Mem0-Client-Language": "node",
	"X-Mem0-Client-Version": CLI_VERSION,
};
```
Sources: [cli/node/src/backend/platform.ts:31-39](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L31-L39)

The internal `_request` method handles execution parameters, query string serialization via `URLSearchParams`, and request timeouts configured at 30 seconds using `AbortSignal.timeout(30_000)` [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L41-L61). It dynamically injects `"X-Mem0-Caller-Type"` as `"agent"` or `"user"` depending on the active execution state checked by `isAgentMode()` [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L52-L55), [cli/node/src/state.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/state.ts#L8-L15).

> [!WARNING]
> When API responses include a `mem0_notice` payload property or an `X-Mem0-Notice-Message` header, the client automatically intercepts and stashes the message via `captureNotice` for end-of-command user surfacing, stripping the property from dictionaries and arrays so downstream consumers never encounter duplicate notices [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L102-L130). Sources: [cli/node/src/backend/platform.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/platform.ts#L102-L130)

## Memory Operations and Lifecycle Workflows

### Execution Flow and Validation

Memory operations in the Node.js CLI are initiated via commands like `cmdSearch`, `cmdList`, `cmdGet`, and `cmdUpdate` which invoke the corresponding methods on the active `Backend` implementation [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L231-L508). Before dispatching requests, handlers enforce validation rules on inputs and CLI options, writing errors to stderr and terminating execution with status code `1` if constraints fail.

| Command Option / Parameter | Validation Rule | Error Message / Action |
| :--- | :--- | :--- |
| `query` (`cmdSearch`) | Must be truthy | `No query provided. Pass a query argument or pipe via stdin.` (Exit `1`) |
| `filterJson` (`cmdSearch`) | Must be valid JSON | `Invalid JSON in --filter.` (Exit `1`) |
| `topK` (`cmdSearch`) | Must be `>= 1` | `--top-k must be >= 1.` (Exit `1`) |
| `threshold` (`cmdSearch`) | Must be between `0.0` and `1.0` | `--threshold must be between 0.0 and 1.0.` (Exit `1`) |
| `pageSize` / `page` (`cmdList`) | Must be `>= 1` | `--page-size must be >= 1.` or `--page must be >= 1.` (Exit `1`) |
| `metadata` (`cmdUpdate`) | Must be valid JSON | `Invalid JSON in --metadata.` (Exit `1`) |

```typescript
setCurrentCommand("search");
if (!query) {
	printError("No query provided. Pass a query argument or pipe via stdin.");
	process.exit(1);
}

let filters: Record<string, unknown> | undefined;
if (opts.filterJson) {
	try {
		filters = JSON.parse(opts.filterJson);
	} catch {
		printError("Invalid JSON in --filter.");
		process.exit(1);
	}
}

const fieldList = opts.fields
	? opts.fields.split(",").map((f) => f.trim())
	: undefined;

if (opts.topK < 1) {
	printError("--top-k must be >= 1.");
	process.exit(1);
}
if (opts.threshold < 0 || opts.threshold > 1) {
	printError("--threshold must be between 0.0 and 1.0.");
	process.exit(1);
}
```
Sources: [cli/node/src/commands/memory.ts:251-278](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L251-L278)

> [!CAUTION]
> Both search and update workflows parse stringified JSON flags (`--filter` and `--metadata`) using raw `JSON.parse` blocks wrapped in `try/catch` statements [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L258-L265), [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L491-L498). Malformed payload strings immediately trigger `process.exit(1)` after printing an error, bypassing any partial batch operations. Sources: [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L258-L265), [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L491-L498)

### Lifecycle Handlers and Asynchronous Timing

Execution progress for remote CRUD and search requests is measured via `performance.now()` coupled with the `timedStatus` asynchronous status wrapper [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L280-L305). The `Backend` interface defines methods for these lifecycle actions, accepting dedicated options interfaces for filtering, pagination, and structural modifications [cli/node/src/backend/base.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts#L75-L116).

```typescript
export interface Backend {
	add(
		content?: string,
		messages?: Record<string, unknown>[],
		opts?: AddOptions,
	): Promise<Record<string, unknown>>;

	search(
		query: string,
		opts?: SearchOptions,
	): Promise<Record<string, unknown>[]>;

	get(memoryId: string): Promise<Record<string, unknown>>;

	listMemories(opts?: ListOptions): Promise<Record<string, unknown>[]>;

	update(
		memoryId: string,
		content?: string,
		metadata?: Record<string, unknown>,
		opts?: UpdateOptions,
	): Promise<Record<string, unknown>>;

	delete(
		memoryId?: string,
		opts?: DeleteOptions,
	): Promise<Record<string, unknown>>;
}
```
Sources: [cli/node/src/backend/base.ts:76-101](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/backend/base.ts#L76-L101)

> [!NOTE]
> When updating a memory entity via `cmdUpdate`, expiration parameters are validated against date formatting rules via `_validateExpires(opts.expires)` before `backend.update` is dispatched with optional content strings, metadata objects, timestamps, and expiration dates [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L500-L508). Sources: [cli/node/src/commands/memory.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/commands/memory.ts#L500-L508)

## Output Formatting and Terminal Presentation

### Terminal Rendering and Multi-Mode Presentations

The output subsystem supports multiple display modalities tailored for interactive terminal sessions, structured data extraction, and autonomous agent pipelines. It implements specialized formatters for textual lists, tabular displays via `cli-table3`, isolated modal frames using `boxen`, raw JSON serialization, and structured JSON envelopes. Symbol selection adapts dynamically between rich Unicode characters and plain text based on standard TTY availability and the presence of the `NO_COLOR` environment variable [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L5-L107), [cli/node/src/branding.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/branding.ts#L40-L43).

| Formatter Function | Target Output Mode | Primary Dependencies & Features |
| :--- | :--- | :--- |
| `formatMemoriesText` | Human-readable text stream | Iterates record collections, formats ISO timestamps via `formatDate`, and appends metadata strings separated by centered dots. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L22-L54) |
| `formatMemoriesTable` | Fixed-width console table | Uses `cli-table3` with word-wrapping enabled, dynamic headers supporting optional score columns, and truncated content strings. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L56-L103) |
| `formatSingleMemory` | Single-record boxed view | Renders content inside a magenta-bordered box via `boxen` with explicit padding and property labels. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L109-L151) |
| `formatAddResult` | CRUD execution feedback | Maps status events (`ADD`, `UPDATE`, `DELETE`, `NOOP`, `PENDING`) to colored status icons and padded labels. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L153-L228) |
| `formatJsonEnvelope` | Standard JSON response wrapper | Packages data payloads alongside execution metadata, execution duration, scope filters, and account notices. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L230-L258) |

```typescript
export function formatMemoriesTable(
	memories: Record<string, unknown>[],
	opts: { showScore?: boolean } = {},
): void {
	const head = opts.showScore
		? [
				accent("ID"),
				accent("Score"),
				accent("Memory"),
				accent("Category"),
				accent("Created"),
			]
		: [accent("ID"), accent("Memory"), accent("Category"), accent("Created")];
	const colWidths = opts.showScore ? [38, 8, 40, 16, 14] : [38, 40, 16, 14];
	const table = new Table({
		head,
		colWidths,
		wordWrap: true,
		style: { head: [], border: [] },
	});
```
Sources: [cli/node/src/output.ts:56-75](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L56-L75)

> [!NOTE]
> When rendering add results containing asynchronous `PENDING` event statuses, `formatAddResult` deduplicates incoming entries sharing the exact `event_id` to prevent repetitive queue notifications in batch ingestion workflows. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L173-L181)

### Branding Elements and Agent Data Sanitization

Branding components provide visual consistency across terminal banners, status messages, and error hints. The ASCII banner renderer computes horizontal padding dynamically against the longest content line and appends a branded footer displaying the current SDK version [cli/node/src/branding.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/branding.ts#L45-L77). For programmatic consumption, `sanitizeAgentData` strips extraneous properties from backend response objects based on command names before wrapping them in `formatAgentEnvelope` [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L271-L390).

```typescript
switch (command) {
	case "add": {
		const items = Array.isArray(data) ? data : [data];
		return items.map((item) => {
			const r = item as Record<string, unknown>;
			if (r.status === "PENDING") return pick(r, ["status", "event_id"]);
			return pick(r, ["id", "memory", "event"]);
		});
	}
	case "search":
		return (data as Record<string, unknown>[]).map((r) =>
			pick(r, [
				"id",
				"memory",
				"score",
				"created_at",
				"categories",
				"expiration_date",
			]),
		);
	case "list":
		return (data as Record<string, unknown>[]).map((r) =>
			pick(r, [
				"id",
				"memory",
				"created_at",
				"categories",
				"expiration_date",
			]),
		);
	case "get": {
		const r = data as Record<string, unknown>;
		return pick(r, [
			"id",
			"memory",
			"created_at",
			"updated_at",
			"categories",
			"metadata",
			"expiration_date",
		]);
	}
	case "update": {
		const r = data as Record<string, unknown>;
		return pick(r, ["id", "memory", "expiration_date"]);
	}
	case "delete":
	case "delete-all":
	case "entity delete":
		return data;
```
Sources: [cli/node/src/output.ts:274-323](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L274-L323)

> [!WARNING]
> Both `formatJsonEnvelope` and `formatAgentEnvelope` automatically inspect transient state notices via `takeNotice()` and inject a `mem0_notice` property into the JSON output when operating on unclaimed Agent Mode accounts, allowing consuming agents to detect provisioning requirements without checking HTTP headers. Sources: [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L249-L255), [cli/node/src/output.ts](https://github.com/blade47/mem0/blob/b7ad69afda6b6ed030347c66d48a13e4de9dec08/cli/node/src/output.ts#L384-L388)

## Related

- [Python CLI Architecture](https://www.doc0.dev/docs/faa36707-7c28-4f69-a18f-700ff61c704e/technical/cli-tools/python-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.
