---
summary: "Implementation plan for the custodian onboarding redesign (living document)"
read_when:
  - You are implementing or reviewing a phase of the onboarding redesign
title: "Onboarding redesign"
---

# Onboarding redesign implementation plan

> **Living document.** This page tracks the custodian onboarding redesign at
> implementation level and is updated as each phase lands. When the last phase
> merges, this page is rewritten as the user-facing onboarding guide and joins
> the docs navigation. It is intentionally not in `docs.json` until then.

## North star

A non-technical user types `openclaw onboard` (or opens the app) and is greeted
by one conversational presence — OpenClaw, the system custodian ("custodian" is
the internal name only; the user always sees "OpenClaw") — that finds their AI,
sets everything up with announced defaults instead of questions, hatches their
agent as a visible identity moment, and stays reachable forever after as the
system's caretaker. Magic by default, one consent boundary, no dead ends.

Design principles (decided, do not relitigate casually):

- **Announced defaults with easy undo** replace blocking questions. The only
  hard requirement is working inference; everything else is an offer.
- **Question zero is the consent boundary**: "Full access" (recommended) means
  discovery is silent and automatic; "Ask first" gates every discovery — AI
  scanning, app scanning, and memory-source scanning alike — behind one
  explicit yes, with a fully manual path that never scans.
- **Conversation as UI with progressive intelligence**: the custodian surface
  exists before any AI works (scripted dialogue), becomes model-backed the
  moment a route verifies, and visibly says so. It never fakes intelligence:
  free-text input before a route verifies gets a graceful "let me get my brain
  working first".
- **The hatch is a ceremony**: same thread, avatar swap, the agent names itself
  and picks its own face. The custodian teaches the hierarchy once: "ask me
  about the system, or just ask your agent — it relays."
- **Trust is tiered by source**: official catalog entries may be preselected;
  third-party ClawHub skills are never preselected regardless of model
  ranking, and their labels say they install the publisher's code.
- **Configured installs are sacred**: re-running onboarding is a verification
  pass. It never re-applies setup and never restarts the Gateway service.
- **The terminal is the fallback, not a question**: prefer the browser
  dashboard when the Gateway can serve it; never ask "terminal or browser?".
- **Weak models get a trimmed surface** (auto `localModelLean`), explained in
  plain words — never in terms of tools, code mode, or context windows.

## Current shipped flow (after phases 1-3)

`openclaw onboard` on a fresh macOS install, happy path — four Enters total:

1. Security note → one Enter to acknowledge (persisted; never asked again).
2. **Question zero**: "How should I set things up?" — Full access (recommended)
   or Ask first. Persisted as `wizard.accessMode`; reruns default to the saved
   choice. Guarded + "configure manually" reaches the provider picker without
   any scanning and skips memory-source scanning too.
3. **Discovery theater**: detects coding CLIs, env keys, and local runtimes;
   quips when coding agents are found; live-tests candidates in order and
   quietly collects failures into one summary line (details behind "See other
   options"). The first working route is announced as a default with a
   one-keystroke path to the full picker; exploring and skipping keeps the
   working route.
4. Fresh installs only: the standard setup plan applies automatically
   (workspace, Gateway service, sessions — the same plan the conversational
   "yes" runs). Configured installs print "already set up" and never touch the
   service.
5. Memory-import offer (Claude Code / Codex / Hermes), skipped when discovery
   was declined. Imports use the final workspace persisted by setup.
6. **App recommendations**: installed apps matched by the verified model
   against official catalogs + ClawHub; official channel plugins arrive
   pre-checked, third-party skills opt-in with a warning label. Skippable;
   kill switch `wizard.appRecommendations`.
7. **Hatch**: the Gateway builds missing Control UI assets in the background.
   Once it serves the dashboard, the browser handoff opens it (GUI) or prints
   a URL without authentication secrets (headless/SSH) and waits for the
   Control UI to connect — "Dashboard connected — continuing in your browser."
   Otherwise, or with `--tui`, the terminal TUI opens seeded with the bootstrap
   hatch message and the agent introduces itself.

Remote-gateway onboarding keeps its legacy conversational handoff
(`handoffMode: "chat"`); setup must apply on the remote gateway.

## Phases

| #   | Phase                                                                                                                                                     | Surface              | Status                                                                                                                            |
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 1   | Installed-app plugin recommendations (scan, candidates, AI matcher, wizard step, `device.apps` node command)                                              | classic + guided CLI | merged ([#109668](https://github.com/openclaw/openclaw/pull/109668))                                                              |
| 2   | CLI custodian spine (question zero, discovery theater, auto-apply + hatch)                                                                                | guided CLI           | merged ([`a83ed13204f1`](https://github.com/openclaw/openclaw/commit/a83ed13204f118adf1009e5ac88d5afe1905b86c))                   |
| 3   | Browser-first handoff (GUI-session detection, wait-for-dashboard-connect, TUI as fallback)                                                                | CLI → web            | merged ([#110054](https://github.com/openclaw/openclaw/pull/110054))                                                              |
| 4   | Web custodian surface (option cards, typed `question` field on `openclaw.chat`, wizard-step mirroring, first-run handoff)                                 | Control UI           | merged ([#110141](https://github.com/openclaw/openclaw/pull/110141), [#110242](https://github.com/openclaw/openclaw/pull/110242)) |
| 5   | Hatch and bootstrap (recommendations store with once-semantics, self-naming birth sequence, auto-hatch handoff after fresh setup; avatar ladder deferred) | agent bootstrap      | merged ([#110173](https://github.com/openclaw/openclaw/pull/110173), [#110331](https://github.com/openclaw/openclaw/pull/110331)) |
| 6   | Custodian presence PR1 (pinned sidebar entry, Ask OpenClaw in Settings, normal-chrome caretaker greeting; event commentary and channel summon are PR2)    | web + channels       | merged ([#110269](https://github.com/openclaw/openclaw/pull/110269))                                                              |
| 7   | Resilience (custodian reachable on broken config, partial-surface salvage, auto-doctor)                                                                   | gateway              | follow-up                                                                                                                         |

## Implementation notes per phase

### Phase 1 — app recommendations (PR #109668)

- Scanner: `src/infra/installed-apps.ts` (TCC-free macOS enumeration; follows
  symlinked `.app` bundles).
- Candidates: official catalogs + ClawHub search, 20s overall budget, graceful
  offline degradation to catalog-only candidates. Catalog entries are package
  manifests without a top-level `id` — candidates are keyed by the resolved
  plugin id (regression-tested against the real bundled catalogs; keying by
  `entry.id` once collapsed the whole catalog and dropped every official
  recommendation).
- AI matcher: one completion on the verified route
  (`src/system-agent/setup-app-recommendations.ts`); no curated bundle-id map —
  the model rejects coincidental name overlaps. Output is bounded by the
  resolved model's own `maxTokens` budget (the stream layer applies it when no
  explicit cap is passed).
- **Supply-chain guard**: ClawHub listing text is publisher-controlled and
  reaches the matcher prompt, so a listing can promote itself to
  "recommended". Only official catalog entries may be preselected; ClawHub
  skills always require an explicit tick and are labeled "third-party ClawHub
  skill; installs its publisher's code".
- Node command `device.apps` (TS node-host, Android envelope parity), sharing
  off by default; gateway kill switch `wizard.appRecommendations`.
- Delivery lives in the classic wizard and guided custodian flow
  (`src/wizard/setup.app-recommendations.ts`); re-targeting to the bootstrap
  tail remains phase 5 (the service already takes an injectable inventory
  source). Once-semantics (offer only until accepted, stored scan) also lands
  with the phase 5 store; today a rerun re-offers.
- Also fixed: custom `completeSetupInference` prompts no longer inherit the
  32-token verification-probe output cap (`SETUP_INFERENCE_TEST_MAX_TOKENS`
  applies to the "reply OK" probe only).

### Phase 2 — CLI custodian spine (PR #109841)

- Flow rework in `src/commands/onboard-guided.ts`; remote-gateway onboarding
  keeps its legacy chat handoff via `handoffMode: "chat"`.
- Question zero persists `wizard.accessMode` ("full" | "guarded"); reruns
  default to the saved choice (accepting the default can never silently
  downgrade guarded to full). Guarded + manual uses
  `listManualSetupInferenceOptions` (config/manifests only, no probing) and
  skips memory-source scanning.
- Discovery: quiet failure collection (single summary line; details behind
  "See other options"), coding-agent quip, announced route default. Session
  counts in the quip are deferred (qualitative only) until a cheap
  session-count seam exists.
- Fresh installs: `applySystemAgentSetup` (the deterministic conversational
  "yes") persists the workspace and starts the Gateway before memory import;
  the terminal hatch uses `launchTuiCli` seeded with the bootstrap message.
  Configured installs (pre-existing model or gateway config — wizard
  timestamps prove nothing, they are shared with configure/doctor):
  verification only — no apply, no Gateway service restart. Only a pending
  onboarding receipt allows an interrupted fresh setup to resume. Apply
  failure falls back to the conversational chat.

### Phase 3 — browser-first handoff (PR #110054, merged)

- `src/commands/onboard-browser-handoff.ts` owns pure graphical-session
  detection (`SSH_CONNECTION`/`SSH_TTY`; `DISPLAY`/`WAYLAND_DISPLAY` on Linux)
  and the 60-second GUI / 300-second SSH wait. Guided onboarding supports
  graphical desktop sessions on macOS, Linux, and Windows; headless/SSH
  sessions print the dashboard URL, and `--tui` forces the terminal hatch.
- `src/commands/control-ui-handoff.ts` owns dashboard targets, served-document
  readiness, and one-time browser pairing for onboarding and
  `openclaw dashboard`. GUI launches receive a one-time bootstrap link; headless/SSH
  output prints a clean URL with manual authentication guidance. Browser
  launch uses the shared `openUrl` helper.
- One resolved target confirms that the Gateway serves the dashboard document,
  captures the pre-launch presence baseline, and waits for a new connection.
  Missing Control UI assets build asynchronously without blocking Gateway
  startup. Connection tracking polls the existing `system-presence` RPC as a
  **CLI-mode loopback client presenting the configured shared secret** — the
  trusted path every `openclaw` command uses. A raw shared-auth Control UI
  client is rejected with "device identity required" on SecretRef gateways.
  The handoff completes only when a connected `openclaw-control-ui`/`webchat`
  presence row is new relative to the baseline (an already-open dashboard
  cannot complete it).
- `gateway.controlUi.enabled: false` short-circuits before any URL is shown.
- Proven end-to-end against an isolated same-config gateway: URL print → real
  browser connect → "Dashboard connected — continuing in your browser" → no
  terminal hatch. An earlier "token mismatch" hold was a test-harness
  artifact — see the testing playbook below.

### Phase 4 — web custodian surface (merged: #110141, #110242)

- `/custodian` page over `openclaw.chat` with the option-card component
  (2-4 cards, one recommended max, always skippable); onboarding chrome via
  `?onboarding=1`; model-setup first-run completion hands off into it.
- Structured questions are a typed additive `question` field on
  `SystemAgentChatResult` (per-option `reply` text; prose always stands alone
  for the macOS app/TUI). Producers: both onboarding welcome variants and
  hosted wizard select/confirm steps with 2-4 closed options — real channel
  wizards render as cards. The PR1 string-marker stopgap was deleted.
- Session ownership is scoped to gateway URL + every presented credential
  (token, password, bootstrap token, stored device token — sticky across
  transient hello drops); failed user turns are never replayable; sensitive
  input is sent verbatim and masked in the transcript.

### Phase 5 — hatch and bootstrap (merged: #110173, #110331)

- Custodian creates a nameless agent (tool call); the agent's bootstrap opens
  with self-naming. PR1 ships the ceremony capped at three beats (name → soul
  line → skills question) and defers the self-drawn avatar/image-gen ladder
  (model-generated candidates → preset marks → keep logo) to a follow-up. Same
  thread, avatar swap; the claw mark stays reserved for the custodian. The
  agreed identity persists twice: into `IDENTITY.md`/`SOUL.md` (what the agent
  reads) and via `openclaw agents set-identity` (what channels and the UI
  display).
- Recommendations (phase 1 service, stored scan with once-semantics) land as
  the last bootstrap step before the bootstrap file is removed: "minimal set
  or maximum convenience?" The bootstrap reads the stored offer via
  `openclaw onboard recommendations --json` (opaque install IDs only) and
  acknowledges it after the choice is handled so it never asks again. Channel
  connect buttons carry per-channel setup playbooks; the agent collects
  credentials conversationally and relays config writes to the custodian
  ("asking OpenClaw…" is the canonical idiom).
- Self-learning is asked, not announced, and doubles as skill-workshop
  consent; describe ClawHub's release-trust, scan, verification, and integrity
  checks plus the publisher-code warning — never imply every release is signed.
- Auto-hatch shipped: a fresh-install setup apply announces the hatch and
  hands off (terminal TUI / `open-agent` for gateway clients); the web page
  lands in agent chat with the "Wake up, my friend!" draft prefilled. The
  handoff fires only on clean post-write verification. Zero agents after
  deletion offering (instead of auto) remains follow-up polish.

### Phase 6 — custodian presence (PR1 merged: #110269; commentary/summon are PR2)

- Shipped in PR1: default-pinned "OpenClaw" sidebar entry (fresh profiles;
  existing users keep saved pins and reach it via customize/More), "Ask
  OpenClaw" as the first Settings entry, and normal-chrome `/custodian` visits
  that request the caretaker greeting (no onboarding welcome variant), with
  Exit setup rendered only in onboarding mode. A docked inline Settings pane
  needs shared conversation-view extraction (follow-up).
- Event-reactive commentary with anti-Clippy guardrails: consequential or
  failed changes only, at most once per settings visit unless asked. The same
  event seam makes the custodian the voice for degraded auth or broken
  channels later.
- Channels: day-to-day invisible (the agent relays); reachable by explicit
  summon and on agent-down events in the same thread, with its own name and
  claw avatar where the platform allows.
- Weak model detected at setup: auto-set `localModelLean`, and the custodian
  says so in plain words with an upgrade offer.
- The custodian knows its internal nickname ("some folks call me the
  custodian — OpenClaw's fine") and always refers to the agent by name.

### Phase 7 — resilience (needs an owner decision before building)

The original sketch — "the custodian must be reachable no matter how broken
the config is" — collides with the repo's security policy: the root guide
states the Gateway **refuses startup** when config is structurally invalid,
and only SecretRef-owner failures degrade into configured-unavailable
capabilities. Serving any surface from an invalid config is a policy change,
not an implementation detail. Two scopes, pick one:

- **Option A (recommended, policy-compliant): CLI-side auto-doctor.** When a
  gateway or CLI start fails with a known-shape invalid config, the CLI offers
  (or with consent runs) `openclaw doctor --fix`, then retries once and
  reports plainly. No gateway behavior changes; the custodian stays reachable
  through the existing degraded-SecretRef path and the terminal.
- **Option B (needs explicit owner sign-off + security review): gateway
  minimal-surface mode.** On structurally invalid config, start a locked-down
  surface serving only the custodian conversation and doctor actions. This
  rewrites the fail-closed startup contract and must define its own ingress
  protection story before any code.

Remaining follow-ups from phases 4-6 (tracked, unscheduled): avatar/image-gen
ladder for the hatch; macOS app rendering of the typed `question` field; a
docked inline Settings pane for the custodian (needs shared conversation-view
extraction); event-reactive commentary and channel summon/agent-down recovery
(phase 6 PR2); automatic `localModelLean` for weak models; whether existing
users' saved sidebar pins should adopt the OpenClaw entry.

The macOS app now follows the same browser-first principle: native onboarding
ends once inference verifies (install + AI setup pages), and Finish opens the
dashboard at `/custodian?onboarding=1`. The native memory-import and
permissions pages left the first-run flow (Settings → Permissions remains);
deleting the now-unreachable native memory-import module is a follow-up.

## Testing and landing playbook (hard-won; read before phases 4-6)

- **`OPENCLAW_STATE_DIR` does not isolate the Gateway service.** The
  LaunchAgent label (`ai.openclaw.gateway`) is machine-global: a fresh-install
  onboarding test with an isolated state dir will REWRITE and RESTART the real
  machine's service (wrapper scripts land inside the isolated dir; the next
  service start breaks when that dir is cleaned). After any fresh-install
  test, restore with `openclaw gateway install --force && openclaw gateway
restart` from the real environment and verify the plist. Product follow-up:
  state-dir-scoped service labels, or onboarding detecting a foreign service.
- **Safe end-to-end harness**: pre-seed the isolated config with a `gateway`
  section (so onboarding takes the configured-install path and never touches
  the service) and run `openclaw gateway run` as a plain foreground process on
  a spare port with a plain token. That harness proved the phase-3 loop,
  including a real browser connect.
- **Auth paths differ by client identity, not only credentials.** Presence and
  other operator reads use a CLI-mode loopback client with credentials from the
  same config. Token-auth gateways require the shared secret; SecretRef/none
  gateways can fall back to trusted-loopback auth without a token. A Control
  UI-identified browser client needs device identity or the secure-context
  loopback grant. A probe authenticating against a gateway that serves a
  DIFFERENT config (see LaunchAgent pitfall) fails with "token mismatch" — that
  artifact briefly held phase 3.
- **Completion probes**: `runSetupInferenceTest` caps the verification probe at
  32 output tokens; custom prompts bypass the cap and are bounded by the
  model's own `maxTokens`. Reasoning models consume that budget with hidden
  reasoning first — an empty-text turn usually means the budget died there.
- **Agent landing needs exact-head hosted CI.** The heavy `CI` workflow may
  not queue on pushes under org load; the maintainer fallback is a
  release-gate dispatch on the PR branch:

  ```bash
  gh workflow run ci.yml --ref <branch> -f target_ref=<head-sha> -f release_gate=true -f pull_request_number=<pr>
  ```

  The run must be on the
  branch ref so `head_sha` matches, and the title becomes
  `CI release gate <sha>`, which `scripts/verify-pr-hosted-gates.mjs`
  accepts. Then `scripts/pr` prepare/merge as usual.

- **Gates that CI enforces beyond focused tests**: docs consistency
  (`pnpm check:docs` after changing docs), oxlint (`no-map-spread`,
  `max-lines` — split files, never suppress), `check:test-types`, knip
  deadcode (export only what prod consumes; route tests through public APIs),
  and the live-test shard classifier
  (`test/scripts/test-live-shard.test.ts` must list any new `*.live.test.ts`).

## Decision log

- Magical scan with kill switch, not consent-first (phase 1; persistent output
  discloses model and ClawHub use before scanning, and the results note repeats it).
- Full vertical including the node `device.apps` command (phase 1).
- Third-party ClawHub skills are never preselected and are labeled as
  installing the publisher's code; official entries may be pre-checked
  (phase 1, shipped security posture).
- Two access cards, not three; consent front-loaded into the choice (phase 2).
- Auto-hatch with announcement, not a blocking button (phases 2/5).
- Browser-first: the terminal hatch is the fallback, never a "terminal or
  browser?" question (phase 3).
- Custodian gets channel presence (summon + recovery), not web/CLI only
  (phase 6).
- Hatch happens in the same thread with an avatar swap; after completion the
  app transitions to the regular UI (phase 5).
- The settings surface keeps the name "Settings"; the custodian lives there
  (and in the sidebar) rather than replacing it (phase 6).
- Option cards are constrained: 2-4 options, exactly one recommended, always
  skippable; the same component serves onboarding and the agent question tool
  (phase 4).
- "Asking OpenClaw…" is the canonical delegation idiom; souls may add flavor,
  the tool narration stays plain (phase 5).
- User-facing copy never says "code mode", "tools", or "context window" when
  explaining weak-model trimming (phase 6).

## Known gaps and follow-ups

- LaunchAgent label is not state-dir-scoped (testing pitfall above; also a
  real multi-instance product gap).
- Recommendations once-semantics and the stored scan (phase 5); reruns
  currently re-offer.
- Session-count quip is qualitative; counts need a cheap session-count seam.
- Browser handoff lands on the normal dashboard; onboarding-mode custodian
  deep-link arrives with phase 4.
