Login isolation
SDK 0.7 defaultsuseMachineLogin to false. The runtime starts with isolated
provider logins, so a Claude or Codex login on the host machine is not silently
reused. BREAKING from SDK 0.6: to keep using machine logins, pass
useMachineLogin: true explicitly:
doctor() reports logins.mode (isolated, machine, or attached) and a
per-provider logins.perProvider map (isolated, shared, or unknown).
Check this before describing which credentials a thread can use.
Isolation covers the providers’ sign-in folders. It does not cover API keys in
your app’s own environment: the runtime inherits your process environment, so
an ANTHROPIC_API_KEY, OPENAI_API_KEY or CURSOR_API_KEY set there is still
visible to it. Pass an env to createAdeChat without them if
your users should only ever run on their own logins and keys.
Provider accounts
SignInHandle also provides submitCode(code) and cancel(). done resolves
to the refreshed account or rejects when sign-in fails or is cancelled. Always
cancel a login the user abandons. The provider account API also has remove,
rename, setDefault, signOut, and refresh.
AccountInfo contains only the public account summary: id, provider,
label, signedIn, isDefault, and optional email, plan, loginBroken,
accentColor, createdAt, and usage. Runtime-only fields such as an
absolute provider config path are removed before the result reaches the host.
list() and refresh() include usage when the runtime has a matching quota
row for that account:
readAt is the quota reading time; note
explains a stale, signed-out, failed, or not-yet-read state. Only accounts with
an instanceId in the usage report receive per-account usage; one-login
providers do not have one.
client.providers.capabilities(provider) returns the runtime’s choices for
permission modes, reasoning effort, fast mode, accounts, sign-in, API keys,
presets and MCP (ProviderCapabilities). It throws unsupported if the runtime does not advertise
provider capabilities.
Credentials and presets
Credentials are stored by the runtime, encrypted with the OS credential store (Keychain on macOS, DPAPI on Windows; on Linux, a file only this user can read).credentials.list() returns summaries with labels, provider, source,
timestamps and a masked tail; the API key value is never returned.
A key is filed under its API vendor, not the harness that uses it: a Claude
thread runs on an anthropic key, Codex on openai, Kimi on moonshotai,
Grok on xai. Other harnesses use their own name (cursor, droid, pi,
opencode, qwen, copilot).
credentials.remove(id, provider?) removes a stored key. Custom endpoint
presets use client.presets.list(), add(input), update(id, patch), and
remove(id). Preset results omit key material.
When a key lives in your own vault instead, pass its id to a thread and supply
the value with resolveSecret:
credentials.list() shows it with source: "host". If
resolveSecret returns nothing, the open fails with invalid_option.
Two harnesses read keys only from a config file: Droid (settings.json) and
OpenCode presets (opencode.json). For those, the runtime writes the key into a
private launch folder under the SDK home while the thread runs, exactly as it
does for a stored key.
Accounts on a thread
Passaccount, credential, or preset when opening a thread to select the
provider instance, stored credential, or endpoint preset. These choices are
saved with the thread and used again if the runtime loses the session and the
SDK recreates it. thread.switchAccount(instanceId) changes the account for a
live thread; check its result because the runtime can report busy,
signed_out, or failed without switching.
Usage limits
New threads default toonUsageLimit: "wait". Choose another policy when
creating the client:
usageLimit fires whenever a thread’s limit state changes:
{ key, sessionId, provider, status }. status is null when the limit
clears; otherwise it carries state (armed, resuming, paused,
opted_out or no_reset), resetAt, fireAt (when the runtime will resume
on its own), and alternateAccount when another signed-in account still has
room.
"failover" continues the interrupted turn on that alternateAccount, once
per limited turn. The runtime picks the account, because it has the quota
reading. With no alternate, the thread waits for the reset. "wait" and
"ask" only emit the event. Threads expose usageLimit.resumeNow() and
usageLimit.continueOnAlternate() for an explicit choice.
Who can manage accounts
Only the client that started the runtime can manage accounts, credentials and presets. The SDK proves it with a secret it hands the runtime at launch, so the agents running inside your chats, which can reach the same runtime, cannot sign your users’ accounts out or touch their keys. A client created withattach: true, or one that found a runtime an earlier copy of your app left
running, cannot manage accounts and gets unsupported. Dispose it, stop that
runtime, and create the client again.
Electron renderers
Account, credential, and preset methods are refused for renderers by default. Enable them only for trusted frames by passingallowAccountManagement to
registerAdeIpc:
accounts.*, credentials.*, and presets.*. Credential
values can cross into main only through credentials.add; list and verify
responses contain summaries, not secret values.