Replace claim_via_device_flow / claimViaDeviceFlow with claim_via_otp /
claimViaOtp. The new flow:
1. POST /api/v1/auth/email_code/ with the user's email
2. Prompt for the verification code (or accept via --code for non-TTY)
3. POST /.../verify/ with {email, code, agent_mode_api_key: <local key>}
4. Backend's verify_email_code runs upgrade-in-place inline and returns
{claimed: true, claimed_at, ...}
No browser open, no localhost:3000 frontend dependency, no 10-minute poll
loop. Just two HTTP calls + an OTP prompt. Same upgrade-in-place
semantics on the backend; same key-value-unchanged guarantee for the
caller.
--code flag still supported on `mem0 init --email` for non-interactive
use (CI, agent-driven claim scripts).
Mirrors the Python implementation in TypeScript:
- New PlatformConfig fields: agentMode, createdVia, claimedAt, defaultUserId.
- agent-detect.ts: detectAgentCaller() — env-var detection covering
CLAUDECODE / CURSOR_AGENT / CODEX_CLI / CLINE / CONTINUE / AIDER /
GOOSE / WINDSURF.
- commands/agent-mode.ts: bootstrapViaBackend() + claimViaDeviceFlow().
- commands/init.ts: decision tree dispatches to bootstrap (positive agent
signal + no email/api-key) or claim (--email with existing agent-mode
config). Raw API key never leaves the device through the claim.
- index.ts: --agent and --source flags added to `mem0 init`. Skip the
preAction auto-fire for init so it can fire its own M1-M6 cli.init.
- telemetry.ts: all cli.* events now carry agent_mode based on
config.platform.agentMode (per growth-doc M4).
End-to-end verified against the sandbox:
bootstrap (CLAUDECODE=1) → config.agent_mode=true → claim via --email →
config.agent_mode=false, claimed_at set, api_key unchanged.
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.