Relevant source files
The following files were used as context for generating this wiki page:
- integrations/openclaw/cli/commands.ts
- cli/node/src/commands/agent-mode.ts
- cli/node/src/index.ts
- cli/node/src/commands/init.ts
- integrations/hermes-plugin-mem0/init.py
- integrations/hermes-plugin-mem0/_backend.py
- cli/node/src/backend/index.ts
- cli/node/src/backend/platform.ts
- cli/node/src/commands/memory.ts
- cli/python/src/mem0_cli/app.py
- cli/node/src/commands/config.ts
- cli/node/src/backend/base.ts
- integrations/openclaw/index.ts
- cli/node/src/state.ts
- scripts/oss-to-platform-migrate.sh
- cli/node/tsconfig.json
- cli/node/src/config.ts
- cli/node/src/output.ts
- cli/node/src/branding.ts
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, cli/node/src/index.ts
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, cli/node/src/backend/platform.ts
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. The root Command instance defines global application properties, sets up positional option parsing via .enablePositionalOptions(), and configures help formatting cli/node/src/index.ts. 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.
Global options registered on the root program include version inspection, output formatting overrides, and agent mode flags cli/node/src/index.ts.
| 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
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, cli/node/src/index.ts
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. 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, cli/node/src/state.ts. Stashing the active command name ensures that JSON error envelopes include accurate command attribution cli/node/src/index.ts.
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
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. Sources: cli/node/src/index.ts
Option Normalization and Entity Resolution
Subcommands process user input by validating authentication credentials and normalizing filtering options cli/node/src/index.ts. Helper routines like checkAgentMode() inspect root options to determine if output formatting should default to agent JSON structures cli/node/src/index.ts, cli/node/src/state.ts.
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.
* 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
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, cli/node/src/config.ts, cli/node/src/config.ts. Values are resolved according to a defined precedence order, where highest priority settings override lower levels cli/node/src/config.ts.
| Precedence Order | Source Layer | Description |
|---|---|---|
| 1 (Highest) | CLI Flags | Direct execution flags such as --api-key and --base-url cli/node/src/config.ts |
| 2 | Environment Variables | Runtime overrides like MEM0_API_KEY, MEM0_BASE_URL, and scoping keys cli/node/src/config.ts, cli/node/src/config.ts |
| 3 | Configuration File | Persistent storage parsed from JSON on disk cli/node/src/config.ts, cli/node/src/config.ts |
| 4 (Lowest) | Defaults | Built-in fallback constants including DEFAULT_BASE_URL (https://api.mem0.ai) and empty default strings cli/node/src/config.ts, cli/node/src/config.ts, cli/node/src/config.ts |
Sources: cli/node/src/config.ts:4-132
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. Sources: cli/node/src/config.ts
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. 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, cli/node/src/config.ts. 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, cli/node/src/config.ts.
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, cli/node/src/config.ts:187-232
Transient Execution State
In parallel with disk persistence, transient runtime state is maintained across command lifecycles cli/node/src/state.ts. 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. 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.
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
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. 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, cli/node/src/backend/index.ts.
| 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} |
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
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. Sources: cli/node/src/backend/platform.ts
SaaS REST API Communication
The PlatformBackend class communicates directly with the Mem0 SaaS platform (api.mem0.ai) cli/node/src/backend/platform.ts. Every HTTP request builds standard diagnostic and authentication headers using the active API key and CLI version metadata cli/node/src/backend/platform.ts.
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
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. 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, cli/node/src/state.ts.
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. Sources: cli/node/src/backend/platform.ts
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. 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) |
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
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, cli/node/src/commands/memory.ts. Malformed payload strings immediately trigger process.exit(1) after printing an error, bypassing any partial batch operations. Sources: cli/node/src/commands/memory.ts, cli/node/src/commands/memory.ts
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. 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.
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
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. Sources: cli/node/src/commands/memory.ts
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, cli/node/src/branding.ts.
| 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 |
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 |
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 |
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 |
formatJsonEnvelope | Standard JSON response wrapper | Packages data payloads alongside execution metadata, execution duration, scope filters, and account notices. Sources: cli/node/src/output.ts |
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
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
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. 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.
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
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, cli/node/src/output.ts
Related
On This Page
OverviewCommand Dispatch and Argument ParsingEntry Point and Program InitializationTelemetry Hooks and State ManagementOption Normalization and Entity ResolutionConfiguration Persistence and State ManagementConfiguration Precedence and Storage MechanicsKey Mapping and Mutation CommandsTransient Execution StateBackend Abstraction and Platform ClientPluggable Interface and Instantiation FactorySaaS REST API CommunicationMemory Operations and Lifecycle WorkflowsExecution Flow and ValidationLifecycle Handlers and Asynchronous TimingOutput Formatting and Terminal PresentationTerminal Rendering and Multi-Mode PresentationsBranding Elements and Agent Data SanitizationRelated