This page covers step-by-step onboarding behavior, outputs, and internals. For a walkthrough, see Onboarding (CLI). For the full CLI flag reference (every --flag, non-interactive examples, provider-specific commands), see apus onboard.

What the wizard does

Fresh local guided onboarding shows a one-line pointer to the security guide and one choice: Quick start or Custom setup. Quick start records the security acknowledgment; Custom setup shows the full security note and asks for confirmation. Quick start reuses detected AI access, verifies it, saves config, and opens the web dashboard with a foreground Gateway. It uses agent name main and full access, leaves telemetry consent unset, and skips route confirmation, memory import, and app recommendations. Ctrl+C stops the Gateway without removing config; apus gateway install enables background operation later.

Custom setup keeps the full guided prompts. If Quick start finds no usable route, it continues with manual provider setup and the remaining guided steps, including Gateway service installation. The Quick start defaults for agent name (main), access mode (full access), and telemetry (consent unset) stay. See Guided default.

The classic wizard (apus onboard --classic) in local mode walks you through:

Remote mode configures this machine to connect to a Gateway elsewhere. It does not install or modify anything on the remote host.

Local flow details

These steps describe the classic wizard. The guided Quick start lane is described above.

Setup mode

- With no configured default model, the menu contains **QuickStart
  (recommended)** (default) followed by **Manual setup**.
- With a configured default model, **Keep existing model config** appears
  first and becomes the default, followed by **QuickStart (recommended)**
  and **Manual setup**.
  An explicit non-`skip` `--auth-choice` or a single provider credential
  flag still configures that provider without changing the existing default
  model, unless the provider requires you to select a model. Multiple
  provider flags require an explicit `--auth-choice`.
- When a migration provider is available, **Import from another agent**
  appears after those setup choices. Selecting it opens a provider list
  with entries such as **Import from Claude**, **Import from Codex**, and
  **Import from Hermes**. Detected sources appear first with their paths;
  other available providers ask for a source path. Explicit import flags
  dispatch the import directly and skip this menu. Use Back from the
  provider list to return to **Setup mode** before an import begins.
- Re-running the wizard does not wipe anything unless you pass `--reset`.
  Reset is a command flag, not a setup-mode choice.
- `--reset-scope` accepts `config` (config only),
  `config+creds+sessions` (default), or `full` (also removes the workspace).
  Before moving state to Trash, the command
  validates TTY availability and rejectable CLI options. Non-interactive
  setup also requires `--accept-risk` before reset. Interactive classic
  setup performs reset before showing its risk acknowledgement; declining
  that prompt does not undo the reset.
- Migration import options (`--flow import`, `--import-from`,
  `--import-source`, and `--import-secrets`) cannot be combined with
  `--reset`; run the import without `--reset`.
- Without `--reset`, invalid config or legacy keys stop the wizard and ask
  you to run `apus doctor` before continuing.

Risk acknowledgment

- The first run asks you to acknowledge that agents are powerful and full
  system access is risky. The wizard stores the acknowledgment in
  `wizard.securityAcknowledgedAt`, so reruns do not ask again.
- Interactive runs show a confirmation prompt; declining cancels setup.
- `--non-interactive` requires `--accept-risk` and exits with an error when
  the flag is missing.
- Interactive classic setup performs `--reset` before this prompt. Declining
  after a reset does not restore state already moved to Trash.

Workspace

- Default `~/.apus/workspace` (configurable).
- The prompt and `--workspace` reject files, non-directory ancestors,
  dangling symbolic links, and symlink loops at the workspace path or any
  ancestor, identifying the failing path. Other inspection failures, such
  as permission errors, are reported, not treated as missing directories.
  Missing directories and symbolic links to existing directories are
  allowed.
- Seeds workspace files needed for first-run bootstrap.
- On rerun, an existing agent roster keeps its fleet-wide workspace unless
  you explicitly confirm the move. Non-interactive reruns warn and preserve
  the current value.
- Workspace layout: [Agent workspace](/concepts/agent-workspace).

Model and auth

- Full option matrix is in [Auth and model options](#auth-and-model-options).

Gateway

- Prompts for port, bind, secret storage, and Tailscale exposure.
- Generates a Gateway secret by default in token mode, without asking you
  to choose token or password. Existing password-mode configs are preserved.
  Use `--gateway-auth password` or `--gateway-password <value>` to choose
  a password explicitly. Tailscale Funnel still requires password mode.
- Keep shared-secret auth enabled even for loopback so local WS clients must authenticate.
- For the generated secret, interactive setup offers:
  - **Generate/store plaintext secret** (default)
  - **Use SecretRef** (opt-in)
  - Classic QuickStart reuses an existing `gateway.auth.token` SecretRef from an
    `env`, `file`, `exec`, or `store` provider for its check and dashboard
    handoff. An unresolved configured ref stops onboarding with remediation
    guidance instead of silently weakening Gateway auth.
- Explicit or existing password mode also supports plaintext or SecretRef storage.
- Non-interactive token SecretRef path: `--gateway-token-ref-env <ENV_VAR>`.
  - Requires a non-empty env var in the onboarding process environment.
  - Cannot be combined with `--gateway-token`.
- Disable auth only if you fully trust every local process.
- Non-loopback binds still require auth.

Channels

- [WhatsApp](/channels/whatsapp): optional QR login
- [Telegram](/channels/telegram): bot token
- [Discord](/channels/discord): bot token
- [Google Chat](/channels/googlechat): service account JSON + webhook audience
- [Mattermost](/channels/mattermost): bot token + base URL
- [Signal](/channels/signal): optional `signal-cli` install + account config
- [iMessage](/channels/imessage): `imsg` CLI path + Messages DB access; use an SSH wrapper when the Gateway runs off-Mac
- Other bundled or separately installed channel plugins can add their own
  onboarding steps. See the complete [channel catalog](/channels).
- DM security: default is pairing. First DM sends a code; approve via
  `apus pairing approve <channel> <code>` or use allowlists.

Web search

- Pick a provider (Brave, Codex Hosted Search, DuckDuckGo, Exa, Firecrawl,
  Gemini, Grok, Kimi, MiniMax Search, Ollama Web Search, Parallel,
  Perplexity, SearXNG, or Tavily) or skip.
- Skip this step with `--skip-search`; reconfigure later with `apus configure --section web`.

Skills

- Reads available skills and checks requirements.
- Lets you choose node manager: npm, pnpm, or bun.
- Installs optional dependencies for trusted bundled skills when the required
  installer is available.
- Skips unavailable Homebrew, uv, and Go installers, then groups the affected
  skills with manual setup guidance. Run `apus doctor` after installing
  the missing prerequisites.

Daemon install

- macOS: LaunchAgent
  - Requires logged-in user session; for headless, use a custom LaunchDaemon (not shipped).
- Linux and Windows via WSL2: systemd user unit
  - Wizard attempts `loginctl enable-linger <user>` so gateway stays up after logout.
  - May prompt for sudo (writes `/var/lib/systemd/linger`); it tries without sudo first.
- Native Windows: Scheduled Task first
  - If task creation is denied, Apus falls back to a per-user Startup-folder login item and starts the gateway immediately.
  - Scheduled Tasks remain preferred because they provide better supervisor status.
- Runtime selection: Node is the primary, default, and recommended runtime. Bun 1.4+ with WAL-reset-safe `node:sqlite` is available as an explicit opt-in.
  QuickStart reports the runtime selected by the install plan, including Bun when no supported Node is available on a Bun-only first install.
- A SecretRef-managed `gateway.auth.token` is validated without copying its
  resolved plaintext value into supervisor service metadata. An unresolved
  token ref blocks daemon installation with remediation guidance.
- If both `gateway.auth.token` and `gateway.auth.password` exist while
  `gateway.auth.mode` is unset, daemon installation blocks until you choose
  a mode explicitly.
- If restarting an installed service fails, setup reports the failure reason
  and recovery commands instead of claiming the service restarted.

Health check

- Starts gateway (if needed) and runs `apus health`.
- `apus status --deep` adds the live gateway health check to status output, including channel checks when supported.

Finish

- Summary and next steps, including iOS, Android, and macOS app options.

If no GUI is detected, the wizard prints SSH port-forward instructions for the Control UI instead of opening a browser. If Control UI assets are missing, the wizard attempts to build them; fallback is pnpm ui:build (auto-installs UI deps).

Remote mode details

Remote mode configures this machine to connect to a Gateway elsewhere. It does not install or modify anything on the remote host.

What you set:

Discovery (optional)

If `dns-sd` (macOS) or `avahi-browse` (Linux) is available, onboarding
offers to search for Bonjour/mDNS gateway beacons before falling back to
manual URL entry. Wide-area DNS-SD discovery is also attempted when
configured. Docs: [Gateway discovery](/gateway/discovery), [Bonjour](/gateway/bonjour).

Connection method

When a beacon is selected, choose direct WebSocket or an SSH tunnel:
- **Direct**: connects over `wss://` and prompts to trust the discovered
  TLS fingerprint (trust-on-first-use pinning; only pinned if you accept).
- **SSH tunnel**: prints an `ssh -N -L 18789:127.0.0.1:<gateway-port> <user>@<host>`
  command using the resolved Gateway service port, with `-p <ssh-port>` when
  advertised. Run it first, then connect to the local tunnel endpoint at
  `ws://127.0.0.1:18789`.

Auth

Enter the configured token or password in **Gateway secret**. The Gateway
accepts either wire field; interactive setup stores the secret as
`gateway.remote.token`, optionally as a SecretRef instead of plaintext.
To connect without a shared secret, leave it blank, decline keeping an
existing credential if offered, and confirm **Continue without a Gateway secret?**.
Reference storage offers that confirmation before asking for the reference.

If the gateway is loopback-only and not discoverable, use SSH tunneling or a tailnet manually. Plaintext ws:// is accepted for loopback, private IP literals, .local, and Tailnet *.ts.net URLs; other private-DNS names need APUS_ALLOW_INSECURE_PRIVATE_WS=1.

Auth and model options

If a provider setup step fails in interactive onboarding (for example a CLI reuse option without a local sign-in), the wizard shows the error and returns to the provider picker instead of exiting. Explicit --auth-choice runs still fail fast for automation.

The model defaults and provider support statements below describe v2026.9.3. Model defaults move with the product baseline, so check Models if you are on a different release.

Anthropic API key
Uses `ANTHROPIC_API_KEY` if present or prompts for a key, then saves it for daemon use.
Anthropic Claude CLI
Preferred local path in interactive onboarding/configure; reuses an existing Claude CLI sign-in when available.
Anthropic setup token
Supports the long-lived token created by `claude setup-token`. Choose
**Anthropic setup-token** during onboarding, or manage it later with
[`apus models auth`](/cli/models#auth-profiles).
OpenAI Code subscription (OAuth)
Browser flow; paste `code#state`.

On a fresh setup with no primary model, sets `agents.defaults.model` to
`openai/gpt-6-astra` through the Codex runtime.
OpenAI Code subscription (device pairing)
Browser pairing flow with a short-lived device code.

On a fresh setup with no primary model, sets `agents.defaults.model` to
`openai/gpt-6-astra` through the Codex runtime.
OpenAI API key
Uses `OPENAI_API_KEY` if present or prompts for a key, then stores the credential in auth profiles.

On a fresh setup with no primary model, sets `agents.defaults.model` to
`openai/gpt-6-astra`. The bare direct-API `openai/gpt-5.6` alias remains
supported and resolves to the same tier.

Adding or reauthenticating OpenAI preserves an existing explicit primary
model, including `openai/gpt-5.5`. If the account does not expose GPT-5.6,
select `openai/gpt-5.5` explicitly; Apus does not silently downgrade it.
xAI (Grok) OAuth
Browser sign-in for eligible SuperGrok or X Premium accounts. This is the
recommended xAI path for most users. Apus stores the resulting auth
profile for Grok models, Grok `web_search`, `x_search`, and `code_execution`.
xAI (Grok) device code
Remote-friendly browser sign-in with a short code instead of a localhost
callback. Use this from SSH, Docker, or VPS hosts.
xAI (Grok) API key
Prompts for `XAI_API_KEY` and configures xAI as a model provider. Use this
when you want an xAI Console API key instead of subscription OAuth.
OpenCode
Prompts for `OPENCODE_API_KEY` (or `OPENCODE_ZEN_API_KEY`) and lets you choose the Zen or Go catalog (one API key covers both).
Setup URL: [opencode.ai/auth](https://opencode.ai/auth).
API key (generic)
Stores the key for you.
Vercel AI Gateway
Prompts for `AI_GATEWAY_API_KEY`.
More detail: [Vercel AI Gateway](/providers/vercel-ai-gateway).
Cloudflare AI Gateway
Prompts for account ID, gateway ID, and `CLOUDFLARE_AI_GATEWAY_API_KEY`.
More detail: [Cloudflare AI Gateway](/providers/cloudflare-ai-gateway).
MiniMax
Config is auto-written. Hosted default is `MiniMax-M3`; API-key setup uses
`minimax/...`, and OAuth setup uses `minimax-portal/...`.
More detail: [MiniMax](/providers/minimax).
StepFun
Config is auto-written for StepFun standard or Step Plan on China or global endpoints.
Standard currently includes `step-3.5-flash`, and Step Plan also includes `step-3.5-flash-2603`.
More detail: [StepFun](/providers/stepfun).
Synthetic (Anthropic-compatible)
Prompts for `SYNTHETIC_API_KEY`.
More detail: [Synthetic](/providers/synthetic).
Ollama (Cloud and local open models)
Prompts for `Cloud + Local` or `Local only` first.
For hosted models without a local Ollama host, choose `Ollama Cloud` (`--auth-choice ollama-cloud`) instead.
The host-backed modes prompt for base URL (default `http://127.0.0.1:11434`), discover available models, and suggest defaults.
`Cloud + Local` also checks whether that Ollama host is signed in for cloud access.
More detail: [Ollama](/providers/ollama).
Moonshot and Kimi Coding
Moonshot (Kimi K2) and Kimi Coding configs are auto-written.
More detail: [Moonshot AI (Kimi + Kimi Coding)](/providers/moonshot).
Custom provider
Works with OpenAI-compatible, OpenAI Responses-compatible, and Anthropic-compatible endpoints.
The API base URL must use `http://` or `https://`; other URL schemes are rejected before verification.

Interactive onboarding supports the same API key storage choices as other provider API key flows:
- **Paste API key now** (plaintext)
- **Use secret reference** (env ref or configured provider ref, with preflight validation)

Onboarding infers image support for common vision model IDs (GPT-4o/4.1/5.x, Claude 3/4, Gemini, Qwen-VL, LLaVA, Pixtral, and similar) and only asks when the model name is unknown.

Non-interactive flags:
- `--auth-choice custom-api-key`
- `--custom-base-url`
- `--custom-model-id`
- `--custom-api-key` (optional; falls back to `CUSTOM_API_KEY`)
- `--custom-provider-id` (optional)
- `--custom-compatibility <openai|openai-responses|anthropic>` (optional; default `openai`)
- `--custom-image-input` / `--custom-text-input` (optional; override inferred model input capability)
Skip
Leaves auth unconfigured.

Model behavior:

Credential and profile paths:

Paths respect $APUS_STATE_DIR. See Auth credential semantics for shared-store and agent-local behavior.

Credential storage mode:

Headless and server setup

Run auth setup on the Gateway host, using the same OS user and state directory as the Gateway. Over SSH, use an interactive terminal:

apus configure --section model

Choose your provider's supported auth method. For a browser OAuth flow, open the displayed URL in your local browser and paste the redirect URL or authorization code back into the terminal on the Gateway host when prompted. If the provider offers device-code login, complete the displayed URL/code in your local browser while the Gateway host's login process waits. The completed login persists the credential on that host in SQLite; no credential file handoff is needed.

For a specific agent, run apus models auth login --provider <id> --agent <agentId> on the Gateway host. See Models CLI and OAuth.

For unattended setup, use a provider API key with non-interactive onboarding. If you use --secret-input-mode ref, make the referenced environment variable available to the Gateway service as well as the onboarding process. See Authentication.

Verify the result on the Gateway host with apus models status (add --agent <agentId> for a specific agent). Remote-client onboarding only configures the local client connection; it does not set up provider credentials on the server. Do not copy auth-profiles.json or replace a SQLite database to transfer a login.

Outputs and internals

Typical fields in ~/.apus/apus.json:

apus agents add writes agents.entries.* and optional bindings.

WhatsApp credentials go under ~/.apus/credentials/whatsapp/<accountId>/. Active sessions and transcripts are stored in ~/.apus/agents/<agentId>/agent/apus-agent.sqlite. The ~/.apus/agents/<agentId>/sessions/ directory is used for legacy migration inputs and archive/support artifacts.

Some channels are delivered as plugins. When selected during setup, the wizard prompts to install the plugin (npm or local path) before channel configuration.

Installed app recommendations

After the model access check succeeds, classic interactive onboarding on macOS scans application names and bundle IDs without requesting macOS privacy permissions. It searches the official plugin catalogs and ClawHub, then asks the configured model to reject false name matches and recommend relevant plugins or skills. Only recommended matches from official plugin catalogs are selected by default; optional matches and all ClawHub skills require an explicit selection.

The results screen lists the detected applications and shows: "App names were matched using your configured model and ClawHub search." Set wizard.appRecommendations to false to disable both this onboarding step and Gateway access to node app inventories. The scan is not used in Quick start, classic QuickStart, or non-macOS onboarding.

Non-interactive setup

--non-interactive requires --accept-risk (acknowledges that agents are powerful and full system access is risky):

apus onboard --non-interactive --accept-risk --skip-health \
  --auth-choice apiKey \
  --anthropic-api-key "$ANTHROPIC_API_KEY"

--mode defaults to local. --json changes output format but does not imply non-interactive mode. For complete flag semantics and Gateway SecretRef examples, see apus onboard. Provider-specific scripts live in CLI automation.

Gateway wizard RPC

Clients (macOS app and Control UI) can render steps without re-implementing onboarding logic.

When setup admission is busy, wizard.start and the model setup start/activation methods return UNAVAILABLE with details.code: "SETUP_ADMISSION_BUSY". This means that the requested operation did not begin: clients can retire that attempt and allow an explicit retry after the competing setup finishes. A terminal wizard error also ends that operation, but does not imply that earlier writes were rolled back. Generic request failures, timeouts, disconnects, and a missing wizard do not establish whether setup ran; clients must preserve that uncertainty rather than automatically retrying or claiming successful activation.

If a Gateway restart loses the in-memory model setup wizard, the Control UI refreshes the saved model and provider state. A configured model is offered for explicit verification and continuation; if none is configured, provider choices become available again without waiting for the old wizard deadline. Failed refreshes retain the recovery guard and can be retried with Check again. Recovery never replays the previous sign-in or answer, treats a saved model as a successful verification, or requires deleting setup state. Model settings that support config hot reload apply without restarting the Gateway.

Signal setup behavior

Related docs