mem0-cli 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mem0_cli/app.py ADDED
@@ -0,0 +1,1021 @@
1
+ """Main CLI application — the entrypoint for `mem0`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as _json
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import typer
10
+ from rich.console import Console
11
+
12
+ from mem0_cli import __version__
13
+ from mem0_cli.branding import BRAND_COLOR, print_error
14
+
15
+ console = Console()
16
+ err_console = Console(stderr=True)
17
+
18
+ # ── Main app ──────────────────────────────────────────────────────────────
19
+
20
+ app = typer.Typer(
21
+ name="mem0",
22
+ help=f"◆ Mem0 CLI v{__version__} · Python SDK\n\n The Memory Layer for AI Agents",
23
+ no_args_is_help=True,
24
+ rich_markup_mode="rich",
25
+ pretty_exceptions_enable=False,
26
+ add_completion=False,
27
+ subcommand_metavar="<command> [options]",
28
+ options_metavar="",
29
+ )
30
+
31
+ # ── Sub-groups (defined here, registered later to control help ordering) ──
32
+
33
+ config_app = typer.Typer(
34
+ name="config",
35
+ help="Manage mem0 configuration.",
36
+ no_args_is_help=True,
37
+ rich_markup_mode="rich",
38
+ )
39
+
40
+ entity_app = typer.Typer(
41
+ name="entity",
42
+ help="Manage entities.",
43
+ no_args_is_help=True,
44
+ rich_markup_mode="rich",
45
+ )
46
+ # entity_app registered after Memory commands to control panel ordering
47
+
48
+
49
+ # ── Helpers ───────────────────────────────────────────────────────────────
50
+
51
+
52
+ def _get_backend_and_config(
53
+ api_key: str | None = None,
54
+ base_url: str | None = None,
55
+ ):
56
+ """Build and return the Platform backend plus the loaded config."""
57
+ from mem0_cli.backend import get_backend
58
+ from mem0_cli.config import load_config
59
+
60
+ config = load_config()
61
+
62
+ if api_key:
63
+ config.platform.api_key = api_key
64
+ if base_url:
65
+ config.platform.base_url = base_url
66
+
67
+ if not config.platform.api_key:
68
+ print_error(
69
+ err_console,
70
+ "No API key configured.",
71
+ hint="Run 'mem0 init' or set MEM0_API_KEY environment variable.",
72
+ )
73
+ raise typer.Exit(1)
74
+
75
+ return get_backend(config), config
76
+
77
+
78
+ def _get_backend(
79
+ api_key: str | None = None,
80
+ base_url: str | None = None,
81
+ ):
82
+ """Build and return the Platform backend."""
83
+ backend, _config = _get_backend_and_config(api_key, base_url)
84
+ return backend
85
+
86
+
87
+ def _resolve_ids(
88
+ config,
89
+ *,
90
+ user_id: str | None = None,
91
+ agent_id: str | None = None,
92
+ app_id: str | None = None,
93
+ run_id: str | None = None,
94
+ ):
95
+ """Resolve entity IDs: CLI flag > config default > None.
96
+
97
+ If any explicit ID is provided, only use explicit IDs (don't mix
98
+ in defaults for other entity types which would over-filter).
99
+ If no explicit IDs, fall back to all configured defaults.
100
+ """
101
+ has_explicit = any([user_id, agent_id, app_id, run_id])
102
+ if has_explicit:
103
+ return {
104
+ "user_id": user_id or None,
105
+ "agent_id": agent_id or None,
106
+ "app_id": app_id or None,
107
+ "run_id": run_id or None,
108
+ }
109
+ return {
110
+ "user_id": config.defaults.user_id or None,
111
+ "agent_id": config.defaults.agent_id or None,
112
+ "app_id": config.defaults.app_id or None,
113
+ "run_id": config.defaults.run_id or None,
114
+ }
115
+
116
+
117
+ def _read_stdin() -> str | None:
118
+ """Read from stdin if it is piped (not a TTY)."""
119
+ if not sys.stdin.isatty():
120
+ return sys.stdin.read().strip() or None
121
+ return None
122
+
123
+
124
+ # ── Global options (shared via callback) ──────────────────────────────────
125
+
126
+
127
+ @app.callback(invoke_without_command=True)
128
+ def main_callback(
129
+ ctx: typer.Context,
130
+ version: bool = typer.Option(False, "--version", help="Show version and exit."),
131
+ ) -> None:
132
+ if version:
133
+ from mem0_cli.commands.utils import cmd_version
134
+
135
+ cmd_version()
136
+ raise typer.Exit()
137
+
138
+
139
+ # ── Memory: add ───────────────────────────────────────────────────────────
140
+
141
+
142
+ @app.command(rich_help_panel="Memory")
143
+ def add(
144
+ text: str | None = typer.Argument(None, help="Text content to add as a memory."),
145
+ user_id: str | None = typer.Option(
146
+ None, "--user-id", "-u", help="Scope to user.", rich_help_panel="Scope"
147
+ ),
148
+ agent_id: str | None = typer.Option(
149
+ None, "--agent-id", help="Scope to agent.", rich_help_panel="Scope"
150
+ ),
151
+ app_id: str | None = typer.Option(
152
+ None, "--app-id", help="Scope to app.", rich_help_panel="Scope"
153
+ ),
154
+ run_id: str | None = typer.Option(
155
+ None, "--run-id", help="Scope to run.", rich_help_panel="Scope"
156
+ ),
157
+ messages: str | None = typer.Option(None, "--messages", help="Conversation messages as JSON."),
158
+ file: Path | None = typer.Option(None, "--file", "-f", help="Read messages from JSON file."),
159
+ metadata: str | None = typer.Option(None, "--metadata", "-m", help="Custom metadata as JSON."),
160
+ immutable: bool = typer.Option(False, "--immutable", help="Prevent future updates."),
161
+ no_infer: bool = typer.Option(False, "--no-infer", help="Skip inference, store raw."),
162
+ expires: str | None = typer.Option(None, "--expires", help="Expiration date (YYYY-MM-DD)."),
163
+ categories: str | None = typer.Option(
164
+ None, "--categories", help="Categories (JSON array or comma-separated)."
165
+ ),
166
+ graph: bool = typer.Option(False, "--graph", help="Enable graph memory extraction."),
167
+ no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph memory extraction."),
168
+ output: str = typer.Option(
169
+ "text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
170
+ ),
171
+ api_key: str | None = typer.Option(
172
+ None,
173
+ "--api-key",
174
+ help="Override API key.",
175
+ envvar="MEM0_API_KEY",
176
+ rich_help_panel="Connection",
177
+ ),
178
+ base_url: str | None = typer.Option(
179
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
180
+ ),
181
+ ) -> None:
182
+ """Add a memory from text, messages, file, or stdin.
183
+
184
+ Examples:
185
+ mem0 add "I prefer dark mode" --user-id alice
186
+ echo "text" | mem0 add -u alice
187
+ mem0 add --file msgs.json -u alice -o json
188
+ """
189
+ from mem0_cli.commands.memory import cmd_add
190
+
191
+ backend, config = _get_backend_and_config(api_key, base_url)
192
+ ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
193
+
194
+ if no_graph:
195
+ graph_enabled = False
196
+ elif graph:
197
+ graph_enabled = True
198
+ else:
199
+ graph_enabled = config.defaults.enable_graph
200
+
201
+ cmd_add(
202
+ backend,
203
+ text,
204
+ **ids,
205
+ messages=messages,
206
+ file=file,
207
+ metadata=metadata,
208
+ immutable=immutable,
209
+ no_infer=no_infer,
210
+ expires=expires,
211
+ categories=categories,
212
+ enable_graph=graph_enabled,
213
+ output=output,
214
+ )
215
+
216
+
217
+ # ── Memory: search ────────────────────────────────────────────────────────
218
+
219
+
220
+ @app.command(rich_help_panel="Memory")
221
+ def search(
222
+ query: str | None = typer.Argument(None, help="Search query."),
223
+ user_id: str | None = typer.Option(
224
+ None, "--user-id", "-u", help="Filter by user.", rich_help_panel="Scope"
225
+ ),
226
+ agent_id: str | None = typer.Option(
227
+ None, "--agent-id", help="Filter by agent.", rich_help_panel="Scope"
228
+ ),
229
+ app_id: str | None = typer.Option(
230
+ None, "--app-id", help="Filter by app.", rich_help_panel="Scope"
231
+ ),
232
+ run_id: str | None = typer.Option(
233
+ None, "--run-id", help="Filter by run.", rich_help_panel="Scope"
234
+ ),
235
+ top_k: int = typer.Option(
236
+ 10, "--top-k", "-k", "--limit", help="Number of results.", rich_help_panel="Search"
237
+ ),
238
+ threshold: float = typer.Option(
239
+ 0.3, "--threshold", help="Minimum similarity score.", rich_help_panel="Search"
240
+ ),
241
+ rerank: bool = typer.Option(
242
+ False, "--rerank", help="Enable reranking (Platform only).", rich_help_panel="Search"
243
+ ),
244
+ keyword: bool = typer.Option(
245
+ False, "--keyword", help="Use keyword search.", rich_help_panel="Search"
246
+ ),
247
+ filter_json: str | None = typer.Option(
248
+ None, "--filter", help="Advanced filter expression (JSON).", rich_help_panel="Search"
249
+ ),
250
+ fields: str | None = typer.Option(
251
+ None,
252
+ "--fields",
253
+ help="Specific fields to return (comma-separated).",
254
+ rich_help_panel="Search",
255
+ ),
256
+ graph: bool = typer.Option(False, "--graph", help="Enable graph in search.", rich_help_panel="Search"),
257
+ no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph in search.", rich_help_panel="Search"),
258
+ output: str = typer.Option(
259
+ "text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
260
+ ),
261
+ api_key: str | None = typer.Option(
262
+ None,
263
+ "--api-key",
264
+ help="Override API key.",
265
+ envvar="MEM0_API_KEY",
266
+ rich_help_panel="Connection",
267
+ ),
268
+ base_url: str | None = typer.Option(
269
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
270
+ ),
271
+ ) -> None:
272
+ """Search memories by semantic query.
273
+
274
+ Examples:
275
+ mem0 search "preferences" --user-id alice
276
+ mem0 search "tools" -u alice -o json -k 5
277
+ echo "preferences" | mem0 search -u alice
278
+ """
279
+ from mem0_cli.commands.memory import cmd_search
280
+
281
+ # STEP 7: stdin fallback for query
282
+ if query is None:
283
+ query = _read_stdin()
284
+ if query is None:
285
+ print_error(err_console, "No query provided. Pass a query argument or pipe via stdin.")
286
+ raise typer.Exit(1)
287
+
288
+ backend, config = _get_backend_and_config(api_key, base_url)
289
+ ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
290
+
291
+ if no_graph:
292
+ graph_enabled = False
293
+ elif graph:
294
+ graph_enabled = True
295
+ else:
296
+ graph_enabled = config.defaults.enable_graph
297
+
298
+ cmd_search(
299
+ backend,
300
+ query,
301
+ **ids,
302
+ top_k=top_k,
303
+ threshold=threshold,
304
+ rerank=rerank,
305
+ keyword=keyword,
306
+ filter_json=filter_json,
307
+ fields=fields,
308
+ enable_graph=graph_enabled,
309
+ output=output,
310
+ )
311
+
312
+
313
+ # ── Memory: get ───────────────────────────────────────────────────────────
314
+
315
+
316
+ @app.command(rich_help_panel="Memory")
317
+ def get(
318
+ memory_id: str = typer.Argument(..., help="Memory ID to retrieve."),
319
+ output: str = typer.Option(
320
+ "text", "--output", "-o", help="Output: text, json.", rich_help_panel="Output"
321
+ ),
322
+ api_key: str | None = typer.Option(
323
+ None,
324
+ "--api-key",
325
+ help="Override API key.",
326
+ envvar="MEM0_API_KEY",
327
+ rich_help_panel="Connection",
328
+ ),
329
+ base_url: str | None = typer.Option(
330
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
331
+ ),
332
+ ) -> None:
333
+ """Get a specific memory by ID.
334
+
335
+ Examples:
336
+ mem0 get abc-123-def-456
337
+ mem0 get abc-123-def-456 -o json
338
+ """
339
+ from mem0_cli.commands.memory import cmd_get
340
+
341
+ backend = _get_backend(api_key, base_url)
342
+ cmd_get(backend, memory_id, output=output)
343
+
344
+
345
+ # ── Memory: list ──────────────────────────────────────────────────────────
346
+
347
+
348
+ @app.command(name="list", rich_help_panel="Memory")
349
+ def list_cmd(
350
+ user_id: str | None = typer.Option(
351
+ None, "--user-id", "-u", help="Filter by user.", rich_help_panel="Scope"
352
+ ),
353
+ agent_id: str | None = typer.Option(
354
+ None, "--agent-id", help="Filter by agent.", rich_help_panel="Scope"
355
+ ),
356
+ app_id: str | None = typer.Option(
357
+ None, "--app-id", help="Filter by app.", rich_help_panel="Scope"
358
+ ),
359
+ run_id: str | None = typer.Option(
360
+ None, "--run-id", help="Filter by run.", rich_help_panel="Scope"
361
+ ),
362
+ page: int = typer.Option(1, "--page", help="Page number.", rich_help_panel="Pagination"),
363
+ page_size: int = typer.Option(
364
+ 100, "--page-size", help="Results per page.", rich_help_panel="Pagination"
365
+ ),
366
+ category: str | None = typer.Option(
367
+ None, "--category", help="Filter by category.", rich_help_panel="Filters"
368
+ ),
369
+ after: str | None = typer.Option(
370
+ None, "--after", help="Created after (YYYY-MM-DD).", rich_help_panel="Filters"
371
+ ),
372
+ before: str | None = typer.Option(
373
+ None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
374
+ ),
375
+ graph: bool = typer.Option(False, "--graph", help="Enable graph in listing.", rich_help_panel="Filters"),
376
+ no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph in listing.", rich_help_panel="Filters"),
377
+ output: str = typer.Option(
378
+ "table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
379
+ ),
380
+ api_key: str | None = typer.Option(
381
+ None,
382
+ "--api-key",
383
+ help="Override API key.",
384
+ envvar="MEM0_API_KEY",
385
+ rich_help_panel="Connection",
386
+ ),
387
+ base_url: str | None = typer.Option(
388
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
389
+ ),
390
+ ) -> None:
391
+ """List memories with optional filters.
392
+
393
+ Examples:
394
+ mem0 list -u alice
395
+ mem0 list --category prefs --after 2024-01-01 -o json
396
+ """
397
+ from mem0_cli.commands.memory import cmd_list
398
+
399
+ backend, config = _get_backend_and_config(api_key, base_url)
400
+ ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
401
+
402
+ if no_graph:
403
+ graph_enabled = False
404
+ elif graph:
405
+ graph_enabled = True
406
+ else:
407
+ graph_enabled = config.defaults.enable_graph
408
+
409
+ cmd_list(
410
+ backend,
411
+ **ids,
412
+ page=page,
413
+ page_size=page_size,
414
+ category=category,
415
+ after=after,
416
+ before=before,
417
+ enable_graph=graph_enabled,
418
+ output=output,
419
+ )
420
+
421
+
422
+ # ── Memory: update ────────────────────────────────────────────────────────
423
+
424
+
425
+ @app.command(rich_help_panel="Memory")
426
+ def update(
427
+ memory_id: str = typer.Argument(..., help="Memory ID to update."),
428
+ text: str | None = typer.Argument(None, help="New memory text."),
429
+ metadata: str | None = typer.Option(None, "--metadata", "-m", help="Update metadata (JSON)."),
430
+ output: str = typer.Option(
431
+ "text", "--output", "-o", help="Output: text, json, quiet.", rich_help_panel="Output"
432
+ ),
433
+ api_key: str | None = typer.Option(
434
+ None,
435
+ "--api-key",
436
+ help="Override API key.",
437
+ envvar="MEM0_API_KEY",
438
+ rich_help_panel="Connection",
439
+ ),
440
+ base_url: str | None = typer.Option(
441
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
442
+ ),
443
+ ) -> None:
444
+ """Update a memory's text or metadata.
445
+
446
+ Examples:
447
+ mem0 update abc-123-def-456 "new text"
448
+ mem0 update abc-123 --metadata '{{"key":"val"}}'
449
+ echo "new text" | mem0 update abc-123
450
+ """
451
+ from mem0_cli.commands.memory import cmd_update
452
+
453
+ # STEP 7: stdin fallback for text
454
+ if text is None:
455
+ text = _read_stdin()
456
+
457
+ backend = _get_backend(api_key, base_url)
458
+ cmd_update(backend, memory_id, text, metadata=metadata, output=output)
459
+
460
+
461
+ # ── Memory: delete ────────────────────────────────────────────────────────
462
+
463
+
464
+ @app.command(rich_help_panel="Memory")
465
+ def delete(
466
+ memory_id: str | None = typer.Argument(None, help="Memory ID to delete (omit when using --all or --entity)."),
467
+ all_: bool = typer.Option(False, "--all", help="Delete all memories matching scope filters."),
468
+ entity: bool = typer.Option(False, "--entity", help="Delete the entity itself and all its memories (cascade)."),
469
+ project: bool = typer.Option(False, "--project", help="With --all: delete ALL memories project-wide."),
470
+ dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be deleted without deleting."),
471
+ force: bool = typer.Option(False, "--force", help="Skip confirmation."),
472
+ user_id: str | None = typer.Option(
473
+ None, "--user-id", "-u", help="Scope to user.", rich_help_panel="Scope"
474
+ ),
475
+ agent_id: str | None = typer.Option(
476
+ None, "--agent-id", help="Scope to agent.", rich_help_panel="Scope"
477
+ ),
478
+ app_id: str | None = typer.Option(
479
+ None, "--app-id", help="Scope to app.", rich_help_panel="Scope"
480
+ ),
481
+ run_id: str | None = typer.Option(
482
+ None, "--run-id", help="Scope to run.", rich_help_panel="Scope"
483
+ ),
484
+ output: str = typer.Option(
485
+ "text", "--output", "-o", help="Output: text, json, quiet.", rich_help_panel="Output"
486
+ ),
487
+ api_key: str | None = typer.Option(
488
+ None,
489
+ "--api-key",
490
+ help="Override API key.",
491
+ envvar="MEM0_API_KEY",
492
+ rich_help_panel="Connection",
493
+ ),
494
+ base_url: str | None = typer.Option(
495
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
496
+ ),
497
+ ) -> None:
498
+ """Delete a memory, all memories, or an entity.
499
+
500
+ Examples:
501
+ mem0 delete abc-123-def-456
502
+ mem0 delete abc-123 --dry-run
503
+ mem0 delete --all -u alice --force
504
+ mem0 delete --all --project --force
505
+ mem0 delete --entity -u alice --force
506
+ """
507
+ # ── Validate mutual exclusion ────────────────────────────────────
508
+ modes = sum([memory_id is not None, all_, entity])
509
+ if modes > 1:
510
+ print_error(
511
+ err_console,
512
+ "Only one of memory ID, --all, or --entity may be used at a time.",
513
+ )
514
+ raise typer.Exit(1)
515
+ if modes == 0:
516
+ print_error(
517
+ err_console,
518
+ "Provide a memory ID, --all, or --entity.",
519
+ hint="Run 'mem0 delete --help' for usage.",
520
+ )
521
+ raise typer.Exit(1)
522
+
523
+ # ── Dispatch ─────────────────────────────────────────────────────
524
+ if memory_id is not None:
525
+ from mem0_cli.commands.memory import cmd_delete
526
+
527
+ backend = _get_backend(api_key, base_url)
528
+ cmd_delete(backend, memory_id, dry_run=dry_run, force=force, output=output)
529
+
530
+ elif all_:
531
+ from mem0_cli.commands.memory import cmd_delete_all
532
+
533
+ backend, config = _get_backend_and_config(api_key, base_url)
534
+ ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
535
+ cmd_delete_all(backend, force=force, dry_run=dry_run, all_=project, **ids, output=output)
536
+
537
+ else: # --entity
538
+ from mem0_cli.commands.entities import cmd_entities_delete
539
+
540
+ backend = _get_backend(api_key, base_url)
541
+ cmd_entities_delete(
542
+ backend,
543
+ user_id=user_id,
544
+ agent_id=agent_id,
545
+ app_id=app_id,
546
+ run_id=run_id,
547
+ force=force,
548
+ dry_run=dry_run,
549
+ output=output,
550
+ )
551
+
552
+
553
+ # ── Config subcommands ────────────────────────────────────────────────────
554
+
555
+
556
+ @config_app.command("show")
557
+ def config_show(
558
+ output: str = typer.Option(
559
+ "text", "--output", "-o", help="Output: text, json.", rich_help_panel="Output"
560
+ ),
561
+ ) -> None:
562
+ """Display current configuration (secrets redacted).
563
+
564
+ Examples:
565
+ mem0 config show
566
+ mem0 config show -o json
567
+ """
568
+ from mem0_cli.commands.config_cmd import cmd_config_show
569
+
570
+ cmd_config_show(output=output)
571
+
572
+
573
+ @config_app.command("get")
574
+ def config_get(
575
+ key: str = typer.Argument(..., help="Config key (e.g. platform.api_key)."),
576
+ ) -> None:
577
+ """Get a configuration value.
578
+
579
+ Examples:
580
+ mem0 config get platform.api_key
581
+ mem0 config get defaults.user_id
582
+ """
583
+ from mem0_cli.commands.config_cmd import cmd_config_get
584
+
585
+ cmd_config_get(key)
586
+
587
+
588
+ @config_app.command("set")
589
+ def config_set(
590
+ key: str = typer.Argument(..., help="Config key (e.g. platform.api_key)."),
591
+ value: str = typer.Argument(..., help="Value to set."),
592
+ ) -> None:
593
+ """Set a configuration value.
594
+
595
+ Examples:
596
+ mem0 config set defaults.user_id alice
597
+ mem0 config set platform.base_url https://custom.api.mem0.ai
598
+ """
599
+ from mem0_cli.commands.config_cmd import cmd_config_set
600
+
601
+ cmd_config_set(key, value)
602
+
603
+
604
+ # ── Entity subcommands ────────────────────────────────────────────────────
605
+
606
+
607
+ @entity_app.command("list")
608
+ def entity_list(
609
+ entity_type: str = typer.Argument(..., help="Entity type: users, agents, apps, runs."),
610
+ output: str = typer.Option(
611
+ "table", "--output", "-o", help="Output: table, json.", rich_help_panel="Output"
612
+ ),
613
+ api_key: str | None = typer.Option(
614
+ None,
615
+ "--api-key",
616
+ help="Override API key.",
617
+ envvar="MEM0_API_KEY",
618
+ rich_help_panel="Connection",
619
+ ),
620
+ base_url: str | None = typer.Option(
621
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
622
+ ),
623
+ ) -> None:
624
+ """List all entities of a given type.
625
+
626
+ Examples:
627
+ mem0 entity list users
628
+ mem0 entity list agents -o json
629
+ """
630
+ from mem0_cli.commands.entities import cmd_entities_list
631
+
632
+ backend = _get_backend(api_key, base_url)
633
+ cmd_entities_list(backend, entity_type, output=output)
634
+
635
+
636
+ @entity_app.command("delete")
637
+ def entity_delete(
638
+ user_id: str | None = typer.Option(
639
+ None, "--user-id", "-u", help="User ID.", rich_help_panel="Scope"
640
+ ),
641
+ agent_id: str | None = typer.Option(
642
+ None, "--agent-id", help="Agent ID.", rich_help_panel="Scope"
643
+ ),
644
+ app_id: str | None = typer.Option(
645
+ None, "--app-id", help="App ID.", rich_help_panel="Scope"
646
+ ),
647
+ run_id: str | None = typer.Option(
648
+ None, "--run-id", help="Run ID.", rich_help_panel="Scope"
649
+ ),
650
+ force: bool = typer.Option(False, "--force", help="Skip confirmation."),
651
+ dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be deleted without deleting."),
652
+ output: str = typer.Option(
653
+ "text", "--output", "-o", help="Output: text, json, quiet.", rich_help_panel="Output"
654
+ ),
655
+ api_key: str | None = typer.Option(
656
+ None,
657
+ "--api-key",
658
+ help="Override API key.",
659
+ envvar="MEM0_API_KEY",
660
+ rich_help_panel="Connection",
661
+ ),
662
+ base_url: str | None = typer.Option(
663
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
664
+ ),
665
+ ) -> None:
666
+ """Delete an entity and ALL its memories (cascade).
667
+
668
+ Examples:
669
+ mem0 entity delete --user-id alice --force
670
+ mem0 entity delete -u alice --dry-run
671
+ """
672
+ from mem0_cli.commands.entities import cmd_entities_delete
673
+
674
+ backend = _get_backend(api_key, base_url)
675
+ cmd_entities_delete(
676
+ backend,
677
+ user_id=user_id,
678
+ agent_id=agent_id,
679
+ app_id=app_id,
680
+ run_id=run_id,
681
+ force=force,
682
+ dry_run=dry_run,
683
+ output=output,
684
+ )
685
+
686
+
687
+ # ── Entity subgroup ──
688
+ app.add_typer(entity_app, name="entity", rich_help_panel="Management")
689
+
690
+
691
+ # ── Management commands ───────────────────────────────────────────────────
692
+
693
+
694
+ @app.command(rich_help_panel="Management")
695
+ def init(
696
+ api_key: str | None = typer.Option(None, "--api-key", help="API key (skip prompt)."),
697
+ user_id: str | None = typer.Option(None, "--user-id", "-u", help="Default user ID (skip prompt)."),
698
+ ) -> None:
699
+ """Interactive setup wizard for mem0 CLI.
700
+
701
+ Examples:
702
+ mem0 init
703
+ mem0 init --api-key m0-xxx --user-id alice
704
+ """
705
+ from mem0_cli.commands.init_cmd import run_init
706
+
707
+ run_init(api_key=api_key, user_id=user_id)
708
+
709
+
710
+ # (entity_app registered at module level, below sub-group definitions)
711
+
712
+
713
+ @app.command(rich_help_panel="Management")
714
+ def status(
715
+ output: str = typer.Option(
716
+ "text", "--output", "-o", help="Output: text, json.", rich_help_panel="Output"
717
+ ),
718
+ api_key: str | None = typer.Option(
719
+ None,
720
+ "--api-key",
721
+ help="Override API key.",
722
+ envvar="MEM0_API_KEY",
723
+ rich_help_panel="Connection",
724
+ ),
725
+ base_url: str | None = typer.Option(
726
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
727
+ ),
728
+ ) -> None:
729
+ """Check connectivity and authentication.
730
+
731
+ Examples:
732
+ mem0 status
733
+ mem0 status -o json
734
+ """
735
+ from mem0_cli.commands.utils import cmd_status
736
+
737
+ backend, config = _get_backend_and_config(api_key, base_url)
738
+ cmd_status(
739
+ backend,
740
+ user_id=config.defaults.user_id or None,
741
+ agent_id=config.defaults.agent_id or None,
742
+ output=output,
743
+ )
744
+
745
+
746
+
747
+ @app.command("import", rich_help_panel="Management")
748
+ def import_cmd(
749
+ file_path: str = typer.Argument(..., help="JSON file to import."),
750
+ user_id: str | None = typer.Option(
751
+ None, "--user-id", "-u", help="Override user ID.", rich_help_panel="Scope"
752
+ ),
753
+ agent_id: str | None = typer.Option(
754
+ None, "--agent-id", help="Override agent ID.", rich_help_panel="Scope"
755
+ ),
756
+ output: str = typer.Option(
757
+ "text", "--output", "-o", help="Output: text, json.", rich_help_panel="Output"
758
+ ),
759
+ api_key: str | None = typer.Option(
760
+ None,
761
+ "--api-key",
762
+ help="Override API key.",
763
+ envvar="MEM0_API_KEY",
764
+ rich_help_panel="Connection",
765
+ ),
766
+ base_url: str | None = typer.Option(
767
+ None, "--base-url", help="Override API base URL.", rich_help_panel="Connection"
768
+ ),
769
+ ) -> None:
770
+ """Import memories from a JSON file.
771
+
772
+ Examples:
773
+ mem0 import data.json --user-id alice
774
+ mem0 import data.json -u alice -o json
775
+ """
776
+ from mem0_cli.commands.utils import cmd_import
777
+
778
+ backend, config = _get_backend_and_config(api_key, base_url)
779
+ ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id)
780
+ cmd_import(backend, file_path, user_id=ids["user_id"], agent_id=ids["agent_id"], output=output)
781
+
782
+
783
+ # ── Help (machine-readable) ──────────────────────────────────────────────
784
+
785
+
786
+ def _build_help_json() -> dict:
787
+ """Build machine-readable JSON describing all CLI commands."""
788
+ commands = {
789
+ "add": {
790
+ "description": "Add a memory from text, messages, file, or stdin.",
791
+ "usage": "mem0 add <text> [OPTIONS]",
792
+ "arguments": {
793
+ "text": {"description": "Text content to add as a memory.", "required": False}
794
+ },
795
+ "options": {
796
+ "--user-id, -u": "Scope to user.",
797
+ "--agent-id": "Scope to agent.",
798
+ "--app-id": "Scope to app.",
799
+ "--run-id": "Scope to run.",
800
+ "--messages": "Conversation messages as JSON.",
801
+ "--file, -f": "Read messages from JSON file.",
802
+ "--metadata, -m": "Custom metadata as JSON.",
803
+ "--immutable": "Prevent future updates.",
804
+ "--no-infer": "Skip inference, store raw.",
805
+ "--expires": "Expiration date (YYYY-MM-DD).",
806
+ "--categories": "Categories (JSON array or comma-separated).",
807
+ "--graph": "Enable graph memory extraction.",
808
+ "--no-graph": "Disable graph memory extraction.",
809
+ "--output, -o": "Output format: text, json, quiet.",
810
+ },
811
+ },
812
+ "search": {
813
+ "description": "Search memories by semantic query.",
814
+ "usage": "mem0 search <query> [OPTIONS]",
815
+ "arguments": {"query": {"description": "Search query.", "required": False}},
816
+ "options": {
817
+ "--user-id, -u": "Filter by user.",
818
+ "--agent-id": "Filter by agent.",
819
+ "--top-k, -k, --limit": "Number of results (default: 10).",
820
+ "--threshold": "Minimum similarity score (default: 0.3).",
821
+ "--rerank": "Enable reranking (Platform only).",
822
+ "--keyword": "Use keyword search instead of semantic.",
823
+ "--filter": "Advanced filter expression (JSON).",
824
+ "--fields": "Specific fields to return (comma-separated).",
825
+ "--graph": "Enable graph in search.",
826
+ "--no-graph": "Disable graph in search.",
827
+ "--output, -o": "Output format: text, json, table.",
828
+ },
829
+ },
830
+ "get": {
831
+ "description": "Get a specific memory by ID.",
832
+ "usage": "mem0 get <memory_id> [OPTIONS]",
833
+ "arguments": {"memory_id": {"description": "Memory ID to retrieve.", "required": True}},
834
+ "options": {"--output, -o": "Output format: text, json."},
835
+ },
836
+ "list": {
837
+ "description": "List memories with optional filters.",
838
+ "usage": "mem0 list [OPTIONS]",
839
+ "arguments": {},
840
+ "options": {
841
+ "--user-id, -u": "Filter by user.",
842
+ "--agent-id": "Filter by agent.",
843
+ "--page": "Page number (default: 1).",
844
+ "--page-size": "Results per page (default: 100).",
845
+ "--category": "Filter by category.",
846
+ "--after": "Created after (YYYY-MM-DD).",
847
+ "--before": "Created before (YYYY-MM-DD).",
848
+ "--graph": "Enable graph in listing.",
849
+ "--no-graph": "Disable graph in listing.",
850
+ "--output, -o": "Output format: text, json, table.",
851
+ },
852
+ },
853
+ "update": {
854
+ "description": "Update a memory's text or metadata.",
855
+ "usage": "mem0 update <memory_id> [text] [OPTIONS]",
856
+ "arguments": {
857
+ "memory_id": {"description": "Memory ID to update.", "required": True},
858
+ "text": {"description": "New memory text.", "required": False},
859
+ },
860
+ "options": {
861
+ "--metadata, -m": "Update metadata (JSON).",
862
+ "--output, -o": "Output format: text, json, quiet.",
863
+ },
864
+ },
865
+ "delete": {
866
+ "description": "Delete a memory, all memories, or an entity.",
867
+ "usage": "mem0 delete [memory_id] [OPTIONS]",
868
+ "arguments": {
869
+ "memory_id": {
870
+ "description": "Memory ID to delete (omit when using --all or --entity).",
871
+ "required": False,
872
+ }
873
+ },
874
+ "options": {
875
+ "--all": "Delete all memories matching scope filters.",
876
+ "--entity": "Delete the entity itself and all its memories (cascade).",
877
+ "--project": "With --all: delete ALL memories project-wide.",
878
+ "--dry-run": "Show what would be deleted without deleting.",
879
+ "--force": "Skip confirmation.",
880
+ "--user-id, -u": "Scope to user.",
881
+ "--agent-id": "Scope to agent.",
882
+ "--app-id": "Scope to app.",
883
+ "--run-id": "Scope to run.",
884
+ "--output, -o": "Output format: text, json, quiet.",
885
+ },
886
+ },
887
+ "import": {
888
+ "description": "Import memories from a JSON file.",
889
+ "usage": "mem0 import <file_path> [OPTIONS]",
890
+ "arguments": {"file_path": {"description": "JSON file to import.", "required": True}},
891
+ "options": {
892
+ "--user-id, -u": "Override user ID.",
893
+ "--agent-id": "Override agent ID.",
894
+ "--output, -o": "Output format: text, json.",
895
+ },
896
+ },
897
+ "config show": {
898
+ "description": "Display current configuration (secrets redacted).",
899
+ "usage": "mem0 config show",
900
+ "options": {"--output, -o": "Output format: text, json."},
901
+ },
902
+ "config get": {
903
+ "description": "Get a configuration value.",
904
+ "usage": "mem0 config get <key>",
905
+ "arguments": {
906
+ "key": {"description": "Config key (e.g. platform.api_key).", "required": True}
907
+ },
908
+ },
909
+ "config set": {
910
+ "description": "Set a configuration value.",
911
+ "usage": "mem0 config set <key> <value>",
912
+ "arguments": {
913
+ "key": {"description": "Config key (e.g. platform.api_key).", "required": True},
914
+ "value": {"description": "Value to set.", "required": True},
915
+ },
916
+ },
917
+ "entity": {
918
+ "description": "Manage entities.",
919
+ "subcommands": {
920
+ "list": {
921
+ "description": "List all entities of a given type.",
922
+ "usage": "mem0 entity list <entity_type> [OPTIONS]",
923
+ "arguments": {
924
+ "entity_type": {
925
+ "description": "Entity type: users, agents, apps, runs.",
926
+ "required": True,
927
+ }
928
+ },
929
+ "options": {"--output, -o": "Output format: table, json."},
930
+ },
931
+ "delete": {
932
+ "description": "Delete an entity and ALL its memories (cascade).",
933
+ "usage": "mem0 entity delete [OPTIONS]",
934
+ "options": {
935
+ "--user-id, -u": "User ID.",
936
+ "--agent-id": "Agent ID.",
937
+ "--app-id": "App ID.",
938
+ "--run-id": "Run ID.",
939
+ "--force": "Skip confirmation.",
940
+ "--dry-run": "Show what would be deleted without deleting.",
941
+ "--output, -o": "Output format: text, json, quiet.",
942
+ },
943
+ },
944
+ },
945
+ },
946
+ "init": {
947
+ "description": "Interactive setup wizard for mem0 CLI.",
948
+ "usage": "mem0 init",
949
+ "options": {
950
+ "--api-key": "API key (skip prompt).",
951
+ "--user-id, -u": "Default user ID (skip prompt).",
952
+ },
953
+ },
954
+ "status": {
955
+ "description": "Check connectivity and authentication.",
956
+ "usage": "mem0 status [OPTIONS]",
957
+ "options": {"--output, -o": "Output format: text, json."},
958
+ },
959
+ }
960
+ return {
961
+ "name": "mem0",
962
+ "version": __version__,
963
+ "description": "The Memory Layer for AI Agents",
964
+ "commands": commands,
965
+ "global_options": {
966
+ "--api-key": "Override API key (env: MEM0_API_KEY).",
967
+ "--base-url": "Override API base URL.",
968
+ "--help": "Show help for a command.",
969
+ "--version": "Show version and exit.",
970
+ },
971
+ "help": {
972
+ "human": "mem0 <command> --help Get help for a command",
973
+ "machine": "mem0 help --json Machine-readable help (for LLM agents)",
974
+ },
975
+ }
976
+
977
+
978
+ @app.command(rich_help_panel="Management")
979
+ def help(
980
+ json: bool = typer.Option(False, "--json", help="Output machine-readable JSON for LLM agents."),
981
+ ) -> None:
982
+ """Show help. Use --json for machine-readable output (for LLM agents).
983
+
984
+ Examples:
985
+ mem0 help
986
+ mem0 help --json
987
+ """
988
+ if json:
989
+ console.print(_json.dumps(_build_help_json(), indent=2))
990
+ else:
991
+ console.print(
992
+ f"[{BRAND_COLOR}]◆ mem0 CLI[/] v{__version__} — The Memory Layer for AI Agents\n"
993
+ )
994
+ console.print("Usage: mem0 <command> [OPTIONS]\n")
995
+ console.print("[bold]Commands:[/]")
996
+ console.print(" add Add a memory from text, messages, file, or stdin")
997
+ console.print(" search Search memories by semantic query")
998
+ console.print(" get Get a specific memory by ID")
999
+ console.print(" list List memories with optional filters")
1000
+ console.print(" update Update a memory's text or metadata")
1001
+ console.print(" delete Delete a memory, all memories, or an entity")
1002
+ console.print(" import Import memories from a JSON file")
1003
+ console.print(" config Manage configuration (show, get, set)")
1004
+ console.print(" entity Manage entities (list, delete)")
1005
+ console.print(" init Interactive setup wizard")
1006
+ console.print(" status Check connectivity and authentication")
1007
+ console.print()
1008
+ console.print(" mem0 <command> --help Get help for a command")
1009
+ console.print(" mem0 help --json Machine-readable help (for LLM agents)")
1010
+ console.print()
1011
+
1012
+
1013
+ # Register config subgroup here so it appears after help in Management panel
1014
+ app.add_typer(config_app, name="config", rich_help_panel="Management")
1015
+
1016
+
1017
+ # ── Entrypoint ────────────────────────────────────────────────────────────
1018
+
1019
+
1020
+ def main() -> None:
1021
+ app()