Skip to content

Wizard RPC parity for non-terminal clients (progress, QR/media, auth-challenge capability) #94661

Description

@bkudiess

Summary

The interactive setup wizard runs locally (terminal clack prompter) and over an RPC protocol so non-terminal clients (the Windows companion app, remote nodes) can drive onboarding (wizard.start / wizard.next / wizard.cancel / wizard.status in src/gateway/server-methods/wizard.ts). The RPC WizardSessionPrompter (src/wizard/session.ts) maps note / select / text / confirm / multiselect into protocol steps — but several onboarding affordances are still delivered through channels the RPC client never sees, so a companion-driven onboarding can stall or dead-end.

#94300 fixed one instance of this (OAuth authorization URLs were only written to gateway stdout; now they ride in-band in the wizard prompt via a presentsAuthChallenge prompter capability). This issue tracks the rest of the parity gap so non-terminal clients can complete onboarding end to end.

Gaps

1. Progress is dropped over RPC

WizardSessionPrompter.progress() returns a no-op update / stop (src/wizard/session.ts). Every spin.update(...) during installs, plugin/channel downloads, device-code/OAuth waits, and gateway health probes is silently discarded for RPC clients, so the companion looks frozen during the slowest parts of onboarding.

Root cause: the wizard RPC is pull-based request/response — wizard.next returns exactly one step and blocks until the runner produces it. Progress updates fire while the runner is mid-operation, when there is no pending step to return.

Proposed direction: let progress() enqueue a non-blocking progress step (the WizardStep schema already has a progress type) that wizard.next returns with done:false; the client re-polls wizard.next without an answer to continue. Requires moving WizardSession from a single pending step to a small step queue, and a documented "progress steps are non-interactive; re-poll without answering" client contract.

2. Connection / device-pairing QR is not available to non-terminal clients

Correction (validated against code): there are two distinct QR surfaces; only one is a gap.

  • Channel-login QR (WhatsApp etc.) — already solved over RPC. web.login.start / web.login.wait (src/gateway/server-methods/web.ts) delegate to the channel plugin's loginWithQrStart / loginWithQrWait and already return qrDataUrl (with refresh via currentQrDataUrl). A companion can drive channel linking today; no new RPC needed. The runtime.log QR in extensions/whatsapp/src/login.ts is just the terminal fallback for the CLI path.

  • Connection / device-pairing QR — the real gap. The OpenClaw mobile app (and Windows companion) scans a QR to connect to the gateway. The gateway already accepts such clients (the native QR/setup-code mobile bootstrap seam in src/gateway/server/ws-connection/message-handler.ts; approval RPCs node.pair.* / device.pair.*). But the produce/display side — the setup-code + QR the device scans — is CLI-only: openclaw qr (src/cli/qr-cli.ts) builds it via resolvePairingSetupFromConfig + encodePairingSetupCode (src/pairing/setup-code.ts) and renders ASCII to stdout. There is no gateway RPC that returns { setupCode, qrDataUrl, gatewayUrl, auth } so a companion / GUI / Control UI can display the connect-QR.

Proposed direction: add a gateway RPC (e.g. pairing.setupCode, scope operator.pairing) that reuses resolvePairingSetupFromConfig + encodePairingSetupCode + renderQrPngDataUrl (src/media/qr-image.ts) to return the setup code and QR data URL. The companion renders the QR; the existing mobile-bootstrap consume seam handles the scan-to-connect.

3. presentsAuthChallenge is an ad-hoc capability

#94300 introduced prompter.presentsAuthChallenge to gate in-band OAuth URLs. Promote it to a documented prompter capability so providers/channels have a stable seam, and sweep the remaining user-actionable runtime.log emissions in onboarding for in-band delivery (e.g. the shared local OAuth path in src/plugins/provider-oauth-flow.ts).

4. Guardrail

Add a seam test asserting that auth/channel onboarding steps never leave a required user action only in runtime.log or progress() — required artifacts (auth URL, QR, code) must appear in a protocol-visible step. Prevents new providers/channels from regressing the class.

Proposed PR breakdown

  1. Progress frames over RPC (gap 1) — core + tests. Status: open as feat(wizard): deliver progress over the RPC wizard protocol #94664. (No protocol schema change — the progress step type already exists.)
  2. Connection / device-pairing QR RPC (gap 2) — add a gateway method (e.g. pairing.setupCode) returning { setupCode, qrDataUrl, gatewayUrl, auth }, reusing existing pairing/QR helpers; companion render follows in openclaw-windows-node / iOS.
  3. Formalize presentsAuthChallenge + leak sweep + guardrail (gaps 3, 4).

Related landed/open work: #94300 (OAuth authorization URL carried in the wizard text prompt) and #94664 (progress). Both were validated to need no rework for this design — OAuth is an in-wizard interactive step (URL belongs in the prompt message), and channel/connection QR are separate companion-driven RPCs, so there is no single field that unifies them.

Each core PR ships the protocol capability and core tests; client rendering (Windows companion, iOS) lands separately.

Why an issue first

These touch the gateway wizard protocol (packages/gateway-protocol schema + src/wizard/session.ts semantics) and a new pairing RPC, which are additive but client-visible, and the companion work spans openclaw-windows-node / iOS. Filing here so maintainers can confirm the shape (progress-step semantics; the pairing.setupCode connection-QR RPC) before the PRs land.

Related: #94300 (OAuth authorization URL in wizard prompts).

AI-assisted: Yes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions