MOLTED EMAIL
CLI Reference

molted adopt

Agent adoption flows (invite & device)

CommandDescription
molted adopt createCreate an invite token for an agent
molted adopt claimClaim an invite token and store credentials
molted adopt requestStart the device flow and wait (up to 15 minutes) for the owner to approve
molted adopt listList pending (unclaimed, unexpired) adoption tokens
molted adopt revokeRevoke an unclaimed adoption token (a claimed token's key stays valid)

Agent context

Adopt handles how new agents join an existing tenant without needing the account's email and password. There are two flows: invite (token-based) and device (approval-based). Use this instead of auth signup when joining an existing tenant. Either way the agent ends up with its own API key (mm_live_...) and is registered as an agent under the invite's label.

Flow 1: Invite token (owner creates, agent claims)

# Owner side (an API key from `auth init`, `auth signup` or an earlier adoption):
molted adopt create --label "outreach-agent" \
  --mailbox <mailboxId> --mailbox <mailboxId> \
  --permissions "read,send" --expires 60
# → { "id": "<uuid>", "token": "ma_inv_...", "label": "outreach-agent",
#     "status": "pending", "scopeAllMailboxes": false, "mailboxScopes": [...],
#     "expiresAt": "...", ... }
# → the token is shown only once: give it to the agent (e.g. via env var or config)

# Agent side (no prior auth needed):
molted adopt claim <token>
# → claims the token, stores the new API key + tenant ID in the active profile
#   (~/.molted/profiles/<profile>.json), then asks GET /v1/agent/setup for the next step
# → { "message": "Token claimed - credentials stored", "tenant_id": "...",
#     "label": "...", "agent_id": "...", "ready_to_send": false,
#     "next_step": { "step": "plan", "owner": "human", "do": "...", "request"?: {...} },
#     "hint": "..." }
# → work the list with `molted doctor` until it says READY TO SEND

Flow 2: Device flow (agent requests, owner approves in the portal)

# Agent side (no prior auth needed):
molted adopt request --label "sales-agent"
# → prints to stderr:
#   Open this URL in your browser: https://molted.email/adopt/K7MQ3X
#   Or enter code: K7MQ3X
#   Waiting for approval...
# → the code is 6 characters and expires after 15 minutes
# → polls every 5 seconds until the owner approves in the portal
# → on approval: stores credentials and prints
#   { "message": "Adopted - credentials stored", "tenant_id": "...", "label": "...", "agent_id": "...", "hint": "..." }

# Owner side: opens the URL signed in to the portal, grants all mailboxes (the default)
# or picks specific ones, and approves. There is no reject button: an unapproved code expires.

Manage pending tokens (owner side)

molted adopt list             # pending (unclaimed, unexpired) tokens
molted adopt revoke <id>      # revoke a token before it's claimed

A key sees every pending token in the workspace if it is an all-mailbox key; a mailbox-scoped key sees, and can revoke, only the invites it created. Revoking only stops an unclaimed token. A claimed token can't be revoked and the key it produced keeps working: revoke that key with molted auth keys revoke <keyId>.

Options on adopt create:

  • --mailbox <id> (repeatable) - grant access to specific mailboxes (UUIDs)
  • --all-mailboxes - grant access to all current and future mailboxes
  • --permissions <perms> - comma-separated, applied to every --mailbox: read, send, manage (default: "read,send")
  • --expires <minutes> - token TTL (default: 1440 = 24h, max: 43200 = 30d)

With neither --mailbox nor --all-mailboxes the invite carries no mailbox access at all, so the claimed key can't read or send anything. Pass one of them.

An agent key may only invite within its own scope: an all-mailbox invite from a mailbox-scoped key, or a mailbox or permission the key lacks, is a human decision (403 human_decision_required, kind "adopt-invite").

When to use adopt vs auth:

  • auth signup - new account, new tenant (you're the owner)
  • auth init - you already have an API key
  • adopt claim - joining an existing tenant with an invite token
  • adopt request - joining an existing tenant without a token (owner approves)

Related: molted auth, molted agents

Commands

molted adopt create

Create an invite token for an agent

molted adopt create [options]
OptionDescriptionDefault
--label <label>Key labelagent
--mailbox <id>Mailbox ID (repeatable)
--permissions <perms>Comma-separated permissions for every --mailbox: read, send, manageread,send
--all-mailboxesGrant access to all current and future mailboxes
--expires <minutes>Expiry in minutes (default: 1440, max: 43200)1440

molted adopt claim

Claim an invite token and store credentials

molted adopt claim [options] <token>
ArgumentDescriptionRequired
<token>yes
OptionDescriptionDefault
--base-url <url>API base URL override

molted adopt request

Start the device flow and wait (up to 15 minutes) for the owner to approve

molted adopt request [options]
OptionDescriptionDefault
--label <label>Suggested key labelagent
--base-url <url>API base URL override

molted adopt list

List pending (unclaimed, unexpired) adoption tokens

molted adopt list

molted adopt revoke

Revoke an unclaimed adoption token (a claimed token's key stays valid)

molted adopt revoke <id>
ArgumentDescriptionRequired
<id>yes

See CLI overview for global options, credentials and output format.