feat(cli): Agent Mode bootstrap + claim flow (Python)
New behavior on `mem0 init`:
- With no `--email`/`--api-key` AND a positive agent signal (`--agent`,
global `--json`/`--agent`, or one of the recognized agent env vars
CLAUDECODE / CURSOR_AGENT / CODEX_CLI / CLINE / CONTINUE / AIDER /
GOOSE / WINDSURF), bootstrap an unattended Agent Mode account via
POST /api/v1/auth/agent_mode/. No email, no OTP, no dashboard.
- With `--email <addr>` AND an existing config that has agent_mode=true,
run the claim device-flow against the existing key instead of minting
a fresh one. The raw API key never leaves the device; backend confirms
claim via the existing CLILoginRequest poll path. Config flips
agent_mode=false and stamps claimed_at on success.
- Bare `mem0 init` with no signal + no TTY still errors out — auto-bootstrap
requires a positive agent signal to avoid surprising pipe-using humans.
New flags:
--agent Force unattended Agent Mode bootstrap.
--source Channel attribution string for signup_source PostHog property.
Config schema extensions on PlatformConfig:
agent_mode, created_via, claimed_at, default_user_id.
Telemetry (M1-M6 from the growth doc):
- cli.init: mode (agent|email|api_key|existing_key), agent_caller,
signup_source, claimed_agent_mode (bool when --email claims an
existing agent-mode config).
- All cli.* events: agent_mode reflects config.platform.agent_mode (the
bootstrap flag), not the output-format flag — per the growth-doc spec.
This commit is contained in:
@@ -236,7 +236,8 @@ def main_callback(
|
||||
_fire_telemetry("version")
|
||||
cmd_version()
|
||||
raise typer.Exit()
|
||||
if ctx.invoked_subcommand:
|
||||
if ctx.invoked_subcommand and ctx.invoked_subcommand != "init":
|
||||
# init fires its own telemetry from init_cmd.run_init with full M1-M6 props.
|
||||
_fire_telemetry(ctx.invoked_subcommand)
|
||||
|
||||
|
||||
@@ -851,6 +852,12 @@ def init(
|
||||
force: bool = typer.Option(
|
||||
False, "--force", help="Overwrite existing config without confirmation."
|
||||
),
|
||||
agent_signal: bool = typer.Option(
|
||||
False, "--agent", help="Bootstrap an unattended Agent Mode account (no email required)."
|
||||
),
|
||||
source: str | None = typer.Option(
|
||||
None, "--source", help="Channel attribution for signup (e.g. github, hn, ph).",
|
||||
),
|
||||
) -> None:
|
||||
"""Interactive setup wizard for mem0 CLI.
|
||||
|
||||
@@ -859,10 +866,20 @@ def init(
|
||||
mem0 init --api-key m0-xxx --user-id alice
|
||||
mem0 init --email alice@company.com
|
||||
mem0 init --email alice@company.com --code 482901
|
||||
mem0 init --agent # Bootstrap an Agent Mode account (unattended)
|
||||
mem0 init --email alice@company.com # Claims an existing Agent Mode key when one is present
|
||||
"""
|
||||
from mem0_cli.commands.init_cmd import run_init
|
||||
|
||||
run_init(api_key=api_key, user_id=user_id, email=email, code=code, force=force)
|
||||
run_init(
|
||||
api_key=api_key,
|
||||
user_id=user_id,
|
||||
email=email,
|
||||
code=code,
|
||||
force=force,
|
||||
source=source,
|
||||
agent=agent_signal,
|
||||
)
|
||||
|
||||
|
||||
# (entity_app registered at module level, below sub-group definitions)
|
||||
|
||||
Reference in New Issue
Block a user