* feat(browser): unify local Chrome setup across desktop and terminal Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * feat(browser): unify local Chrome setup across desktop and terminal OpenClaw-Publication: d19e865e-b5a0-4c70-8876-c1662f6e7ef2 Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * chore(linux): format Chrome setup fixture Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * feat(browser): keep desktop Chrome setup local and preserve pairing Delegate Windows registration to the shared native management owner, preserve released native bridge compatibility and saved launcher profiles, and integrate serialized desktop setup through isolated local runtimes. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): repair native setup CI contracts Keep Windows installer dependencies acyclic, validate Unicode within the package library target, and remove unused private exports. Require all eight packaged native-host proof cases and update lazy CLI inventory. Apply native Swift formatter diagnostics without changing behavior. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(cli): account for plugin-owned browser extension catalog Keep the core-only registration invariant aligned with the Browser plugin owner already exercised by its lazy registration tests. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(macos): retain released Chrome bridge request expectation Align the native bridge test with the shipped contract1 request retained by the canonical setup owner, and reject extra legacy payload fields. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(tui): give command handler harness a unique export Rename the shared TUI test helper and both consumers to avoid the Gateway placement harness export collision. No alias or guard waiver. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * chore(sdk): allow canonical browser config path resolver Apply the approved single public-export and callable allowance for resolveConfigPath. Preserve canonical pre-config path ownership and all other SDK surface checks. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve desktop setup selection and supported actions Keep native automatic setup selector-free and resolve saved local browser selection through the canonical setup owner before installation. Respect Mac action advertisements and the released legacy install projection in the Apps card, and document the public config-path resolver contract. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(auth): retry model selection after concurrent credential refresh Adopt upstream PR #152426, commit32298b10f6, without changing its five source files. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test: preserve native setup selection and await dashboard document Match the selector-free native CLI arguments exactly and preserve a saved work-profile result. Wait through the existing document-readiness owner only at the quota test browser-proof boundary, after auth assertions. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(ui): avoid preloading already imported modules Remove exact direct static JavaScript imports from lazy preload tables using the emitted build graph. Preserve HTML, lazy-only JavaScript, CSS, and locale hints. Source-exact CI merge reproduction drops startup gzip from 363283 to 362968 bytes without changing budgets. Add a real emitted-bundle regression. Apply rustfmt layout to the native Chrome selector-free expected arguments. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix: preserve Chrome profiles and attachment follow-up branch binding Let the TUI canonical setup controller retain its saved browser profile and project only a bounded returned name. Align both native first-run fixture expectations with selector-free setup. Join pending chat history before the composer task handoff can expose an admitted attachment to restored-outbox delivery. Preserve idempotency, attachment custody, restored delivery semantics, and all existing assertions and timeouts. Add a deterministic regression reproduced on the exact failed CI merge and its main parent. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(state): adopt canonical worker-custody fixture repair Adopt src/plugin-state/plugin-state-worker.test.ts byte-for-byte from upstreambfec65a2a0(#152456). The former fixture held its late competing owner until after awaiting off-thread acquisition. Preserve that overlap, assert continued host authority checks and noncompletion, release custody, then assert the original result and persisted state. No production locking, guard, deadline or outcome assertion is relaxed. Both prior failures reproduced on the exact CI main parent with independently installed frozen dependencies and Node 24.19.0. All 12 repaired file tests, selected state-logging types, scoped typed lint and fresh P0-P2 review passed. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): retain saved Windows setup profiles Recover configured extension profiles through bounded serial read-only C# inspection. Select only independently validated current matching descriptors, confirm the selected generation before effects, and leave the single mutation under the existing C# owner. Preserve POSIX behavior, existing manual relay verification and explicit same-profile repair. Missing descriptors, runtime/origin drift and unknown or changing observations fail closed without automatic mutation. Keep raw management facts private and populate the existing browserProfile field only from validated binding metadata. No ABI, schema, SDK, configuration flag or registry/activation owner change. 29 actual CLI/controller/Windows-adapter boundary cases plus sibling coverage: 94 tests pass. Canonical changed checks, full production build and fresh independent P0-P2 review passed. Actual C# native proof remains separately coordinated. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve saved profiles after POSIX bundle relocation Separate validated native registration ownership from supported origin-migration readiness. Recover the profile only after full private manifest and exact launcher validation; preserve the existing one-slot migration rule and all unsupported-origin, ACL and foreign-host refusals. Fail closed before selector-free installation when the saved selection cannot be proved. Extract the unchanged shared origin helpers into a cohesive sibling to satisfy the existing line-cap guard without waivers. Windows admission, ABI and selector behavior remain unchanged. Actual Linux/Darwin CLI-to-filesystem relocation regressions: 18 failures on original production, all 22 cases repaired. Preserve the private relay key and inode, config, Chrome preferences, work relay19444 and explicit-profile intent. 137 focused tests, eight real POSIX native-host E2E cases, canonical changed checks, full production build and fresh P0-P2 review passed. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(ui): retain input handoff through the shared outbox owner Remove the superseded pending-history no-yield workaround after main introduced foreground submission custody in the shared outbox owner. Restore chat-submit-guard.ts exactly to pinned main cc7 rather than retaining competing timing policies. Keep passive drains fenced while the input task yields. Preserve the retained history regression with explicit MessageChannel admission, no passive send before resume, and the same terminal leaf, idempotency key, attachment bytes and exactly-once assertions after completion. Original composed source fails all five focused cases; the repair passes 67 handoff/attachment cases and 20 real Chromium cases in the canonical secretless network-none runner. Canonical checks, UI build/performance and fresh P0-P2 review pass. No assertion, timeout, origin or proxy-policy weakening. Browser POSIX/Windows repairs remain byte-identical to accepted255f. The failed e40e CI receipts remain preserved; fresh exact-head CI and parent handoff are still required. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(tasks): preserve reads across native event finalization Hand joined event publication to its exact native successor after the native flow and observer publication frame completes. Keep worker settlement and cleanup, reversible claim transfer, current-authority and ABA checks, and post-commit delivery in their existing owners without replaying writes. Cover pre-result and readback finalization, native and reentrant successor chains, rollback, failed publication, delivery, and terminal activity cleanup. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(ui): retain rail baseline geometry on readiness failure Keep the exact existing readiness predicate, fixtures, case inventory, assertion and timeout. When the predicate is false, retain synthetic marker identity and numeric geometry so hosted CI can distinguish scroll, visibility and viewport failures. This is diagnostic evidence, not a repair or waiver of the unresolved rail failure. Local rootless browser infrastructure is unavailable; the existing hosted CI lane will verify the reviewed task-publication repair and collect meaningful rail evidence. Canonical changed checks and P0-P2 diagnostic review pass. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * docs(linux): describe saved-profile Chrome setup selection Match the selector-free adapter argument vector and its regression test. Address the fresh P3 review finding without changing runtime behavior. Markdown syntax and diff checks pass; the generic formatter excludes this subtree. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(transcripts): join configured startup before cleanup faults Observe and await the real startTranscripts promise through a narrow call-through spy while retaining the configured service entry point and real SQLite/provider work. Bind the await to the existing test lifetime instead of charging startup to the subsequent short active-map poll. Gate provider return after persisted utterance to prove readiness does not settle early; retain both missing/unreadable row injections and all cleanup, private-source, lifecycle-token and summary assertions. Cover real startup rejection explicitly. No production change, timeout increase, retries or broad module/storage mocks. The deterministic ordering boundary fails with the old fire-and-forget readiness and passes with the real promise join. Final 39 tests across 3 files, canonical changed checks and full-owner P0-P2 review pass. This does not recover whether the historical CI startup was late or rejected. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve automatic desktop status inspection Restore read-only Device-page inspection for current and released Mac bridges while keeping installation and verification explicit. Preserve the native filesystem prerequisite proof, split installer repair tests within the existing line cap, and remove the superseded constant export. * fix(browser): preserve registered setup configuration Require canonical setup to match an owned launcher's effective state and config selection before installation or relay access. Preserve equivalent implicit/explicit default selections and the saved launch context. Recheck automatic profile selection before effects and the current manifest before publication through the existing registration owner. Keep manual install and relocation repair contracts unchanged. Cover mismatched configs, legacy selectors, equivalent defaults, selection drift, and actual bootstrap after refused setup. Restore the missing Command import in the existing Unix-only companion CLI test. Focused tests, types, lint, fresh review, clean package build and sealed Mac ARM64 runtime proof pass. The separate historical clock-jump CI failure has bounded replay evidence and remains documented without a speculative fix. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * fix(browser): keep setup registration types acyclic Move the private registration status contract beside its context policy and point both consumers at that owner. Remove the publication-module back-edge without keeping an unused compatibility export. The full architecture gate, extension production/test types, typed lint and fresh independent review pass. Node's transformed JavaScript is byte-identical for all three affected modules, so the existing runtime proof remains valid. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * test(linux): handle Chrome setup in desktop sharing fixture Recognize the exact automatic Chrome setup invocation and require its native no-respawn flag. Keep unknown-command rejection, selected-auth validation, process-group ownership and joined teardown assertions unchanged. The original fixture reproduces the CI rejection against the real Linux app. The repaired fixture passes all nine checks against that same binary, with five Chrome setup calls and five node starts and joined stops. Fresh review is clean; production app behavior is unchanged. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> --------- Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
32 KiB
OpenClaw for Linux
The Linux companion is a Tauri v2 desktop shell for local and remote OpenClaw Gateways. It discovers nearby Gateways over Bonjour, installs the CLI when local setup needs it, delegates local Gateway service management to openclaw gateway, opens the selected Gateway's Control UI, and stays available in the system tray.
On macOS, the Tauri build is named OpenClaw-Tauri so it can be installed alongside the native OpenClaw app. It retains its separate bundle identity when updated.
Dashboard widgets and browser panels load inside the app. Browser tabs belong to their conversation and support back, forward, reload, stop, snapshots, element inspection, and saving the current page or asset. Opening the same address in a conversation reuses its tab; other conversations keep their own tabs. Popups opened by a browser tab stay in that conversation.
Reading tabs share a private browser session, isolated from the dashboard's native commands and authentication scripts. Closing every reading tab, switching Gateways, or quitting the app ends that private session. Reloading the dashboard retains its tabs. Sign-in links and Open in browser continue to use your system browser.
Startup, setup, connection recovery, Manage Gateways, and Quick Chat share the web UI's typography and light/dark palettes. They follow system appearance changes while open, preserving connection drafts, credential visibility, and Quick Chat replies. The connected dashboard retains its own web UI appearance setting.
Quick Chat places the latest reply above a single bottom composer. Its disclosure button collapses the reply while retaining streamed text, widget contents, and the next draft. Return sends; Shift-Return adds a newline. The next draft remains editable while a reply streams, and sending becomes available when that turn finishes. Open dashboard opens the Primary Gateway's full interface.
During remote setup or in Connection Settings, choose token or password under Authentication. Show credential reveals only what you entered; changing authentication types clears that draft and masks the new field. Press Enter or Connect to Gateway to connect. Leave credentials blank in Connection Settings to reuse saved credentials for the same endpoint.
The tray's Stop Gateway and Restart Gateway actions request graceful shutdown. Running work can delay completion; Start Gateway brings a stopped local Gateway back online.
After a connection drops, the companion keeps reconnecting while the service state is unknown. Start Gateway remains available only for a confirmed stopped service.
The companion uses a unified title bar that blends into the dashboard. Drag the empty header space, a session title, or the thin strip below the top resize edge to move the window. Double-click those areas to maximize or restore it; buttons and editable content keep their normal behavior. The window edges still resize. Linux and Windows builds place minimize, maximize/restore, and close at the top right. macOS test builds retain native traffic lights at the top left. Closing the main window keeps the companion in the tray; closing a separate discovered Gateway window closes that window. While a page loads, redirects outside the dashboard, or opens a modal dialog, Linux and Windows keep the system title bar available until the companion's controls can receive input again. Dashboards opt into the unified title bar only when their UI supports its layout and modal handling. Older Gateways keep the system title bar and their existing dashboard controls; update the Gateway to enable the unified layout.
Published AMD64 AppImages are built on Ubuntu 22.04 and require glibc 2.35 or
newer plus a libstdc++ that provides GLIBCXX_3.4.30. Ubuntu 22.04 and
Debian 12 meet that ABI floor. RHEL 9 and Rocky Linux 9 ship glibc 2.34, so
they cannot run the published AppImage. Extraction does not bypass this
requirement.
See Desktop compatibility for package updates, desktop limitations, and native-app distinctions.
New Session uses Cmd+Shift+O on macOS and Ctrl+Shift+O on Linux and Windows
only while its dashboard is focused. Quick Chat keeps the separate global
Cmd+Shift+Space or Ctrl+Shift+Space shortcut, including when another app is
in front.
Chrome setup bridge
The selected main dashboard can explicitly inspect, install, or verify Chrome setup on the computer running the companion, including when the dashboard's Gateway is remote. Loading the dashboard does not run setup. Chrome retains its extension installation approval; the companion does not ask for a pairing key.
The dashboard adapter is
window.webkit.messageHandlers.openclawDeviceSettings.postMessage({type: "chrome-extension-setup", action}),
where action is inspect, install, or verify. Its Promise resolves directly
to the canonical CLI setup JSON, including pending and blocked results, and
rejects on transport, invalid-action, or CLI execution errors. It shares the
existing native browser document token, origin/path, and generation checks;
reading tabs and other dashboard windows do not receive this bridge.
The adapter invokes only
openclaw browser extension setup --action ACTION --json --wait-ms 1000
through the companion's local CLI owner. Profile selection is left to the CLI so
a saved profile is not overridden. Callers cannot choose commands, paths,
profiles, or URLs. Platform bootstrap support comes from the CLI result rather
than the app platform: a Windows app build alone does not establish that native
host bootstrap is supported or verified.
Omarchy
The optional Omarchy 4 bar plugin provides agents, sessions, and quick prompts. With the matching desktop app running, it uses the app’s Primary Gateway and keeps a single visible OpenClaw icon. See Omarchy support for installation, app handoff, shortcuts, and troubleshooting.
Linux prerequisites
Debian and Ubuntu development packages:
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \
libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev \
patchelf xdg-utils
Install a current stable Rust toolchain with rustup.
Media codecs
The companion uses GStreamer plugins for audio and video playback.
WebM/VP9, Opus, Vorbis, and WAV normally work through plugins-good.
H.264/MP4, AAC, and MP3 require the libav and/or plugins-bad packages.
The .deb uses the host's plugins and declares all three packages as
dependencies. The AppImage bundles the GStreamer media framework and the
plugins required for the formats above. For a source build or when rebuilding
either Linux bundle, install the packages and inspection tool explicitly:
sudo apt update && sudo apt install gstreamer1.0-libav gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-tools patchelf xdg-utils
The packaging script stages only that media capability set before Tauri invokes linuxdeploy. This prevents optional host plugins from adding unrelated system libraries to the AppImage dependency closure.
The packaging flow provisions Tauri's five AppImage tools into a clean, digest-pinned cache. After Tauri builds the AppImage, the finalizer re-verifies that cache, removes bundled Wayland client libraries from the retained AppDir, and rebuilds the artifact. WebKitGTK and Mesa then use one compatible host stack.
Develop and build
The companion frontend is static HTML, CSS, and JavaScript. Install repository dependencies once before building:
pnpm install
cd apps/linux/src-tauri
cargo run
cargo build
The app uses OPENCLAW_DESKTOP_CLI when set. Otherwise it checks ~/.openclaw/bin/openclaw, then openclaw on PATH.
Desktop notifications use each platform's system notification service. macOS 13+ uses Apple's User Notifications framework; Windows uses native system toasts and Linux uses the desktop notification service through notify-rust. On macOS, test notifications from a signed .app bundle: a direct cargo run stays unbundled, so the app disables notifications instead of initializing Apple's framework with no bundle identity.
On macOS, a test launch with an isolated HOME or CFFIXED_USER_HOME can make
the user's default keychain unavailable to that process. The saved-Gateway notice
describes the app's launch environment; it does not mean the Mac has no login
keychain. Keep credential-free tests isolated and treat saved-Gateway storage as
unavailable in that fixture. Do not restore the user's keychain or redirect the
test to real credentials to silence the notice. For an installed app, quit and
reopen it from Finder to use the normal login environment. If the configured
keychain is still unavailable, check its configuration in Keychain Access before
attempting any repair.
Inline browser live regression on Linux
The existing first-run driver also exercises real native WebKit browser views
against a synthetic Gateway. In addition to the driver's AT-SPI, Xvfb, and D-Bus
packages, install xdotool for pointer input. With an unbundled development binary:
xvfb-run -a -s '-screen 0 1280x1024x24' dbus-run-session -- \
/usr/bin/python3 apps/linux/tests/first_run.py \
apps/linux/src-tauri/target/debug/openclaw-desktop --inline-browser
This scenario checks real pointer input to the dashboard and native child,
element inspection, PNG snapshots, navigation history, and dashboard reload
persistence. It then uses the app's dashboard deep link to replace the dashboard
in the same process and verifies that a new browser tab works, saves the fixture
bytes through the native chooser, and cancels a second save. The driver owns
an isolated temporary HOME, loopback fixture, and read-only fixture CLI; no real
Gateway or account is used. Add --artifacts-dir DIRECTORY to retain native
screenshots and JSON results
outside the repository. Screenshot capture also requires ImageMagick.
Inline browser live regression on Windows
Start an isolated candidate app with a loopback WebView2 debugging endpoint and load its loopback Gateway dashboard. Once the dashboard is ready, run this from the repository root using the repository's supported Node version:
node apps/linux/scripts/test-inline-browser.mjs --endpoint http://127.0.0.1:9223
The script uses the real dashboard bridge and native child WebViews. It serves synthetic pages on a separate loopback port and checks navigation, SPA history, conversation ownership and deduplication, popups, shared browser cookies, presentation scopes, snapshots, element inspection, dashboard reload persistence, and cleanup. It does not launch the app, change Gateway settings, or contact external sites. It closes only the tabs and scopes created by its run.
Use --dashboard-url http://127.0.0.1:PORT/ to select the candidate dashboard when
multiple local dashboards are open. JSON results and PNG snapshots go to a unique
OS temporary directory; --output DIRECTORY selects another proof location.
Keep these generated proofs outside the repository.
Add --hold to retain the synthetic pages for native screenshots and save-dialog
checks. Create the printed continue file or press Ctrl+C to finish cleanup.
Native visibility and download dialogs still need this UI verification; the
automated scope checks verify the child viewport dimensions and retained tabs.
The script exits nonzero on assertion or cleanup failure. --help describes all
options without connecting to the app.
Native title bar regression on Linux
The first-run driver can exercise window movement and controls through real X11
pointer input. Install openbox, wmctrl, xdotool, x11-utils, and
ImageMagick alongside the driver's Xvfb, D-Bus, and AT-SPI dependencies, then run:
xvfb-run -a -s '-screen 0 1440x1000x24' dbus-run-session -- \
/usr/bin/python3 apps/linux/tests/first_run.py \
apps/linux/src-tauri/target/debug/openclaw-desktop --window-chrome \
--artifacts-dir /tmp/openclaw-window-chrome-proof
The driver creates an isolated HOME and desktop session. It checks drag geometry, double-click maximize/restore, caption buttons, corner resizing, and closing to the tray. Screenshots and observed window geometry remain in the artifact directory. This X11 proof does not replace testing a Wayland compositor.
Native Gateway switching regression on Linux
The same isolated driver covers saved connections, window reuse, restart
selection, and failed-connection recovery. Install gnome-keyring alongside the
native title bar test dependencies, then run:
xvfb-run -a -s '-screen 0 1440x1080x24' dbus-run-session -- \
/usr/bin/python3 apps/linux/tests/first_run.py \
apps/linux/src-tauri/target/debug/openclaw-desktop --gateway-switch \
--artifacts-dir /tmp/openclaw-gateway-switch-proof
The driver owns its temporary HOME and Secret Service. It verifies that ordinary window selection leaves the Primary configuration unchanged. The Linux App workflow runs this scenario and retains its screenshots and results.
Use --gateway-onboarding in place of --gateway-switch to exercise local
installation with a synthetic installer, leave Model Setup, and verify native
window controls and Gateway actions under a non-root Gateway path. This scenario
uses the same isolated fixtures and also runs in the Linux App workflow.
First-run setup
The welcome screen explains what OpenClaw can do and asks where your assistant should live:
- On this computer installs the CLI and managed Node runtime when needed, then starts the Gateway as a systemd user service. Release builds install the stable channel automatically; development builds ask for a release channel and preselect Development.
- On another computer connects to an existing Gateway without installing or
starting a local Gateway service. Select a nearby discovered Gateway, enter a
Gateway URL directly, or choose SSH tunnel and enter
user@gateway-host. Expand Gateway authentication to provide either the Gateway token or its password when the remote host requires one.
Public direct connections must use HTTPS or secure WebSockets. Plain HTTP or WebSockets are appropriate only for loopback, trusted private networks, or a Tailnet. If the Gateway configuration specifies a TLS certificate fingerprint, choose SSH tunnel: the embedded browser cannot enforce certificate pins, so the app safely refuses direct connections instead of exposing your credentials. Saved remote credentials support literal values and environment- or file-backed secret references; exec and shared-store references must be resolved on their owning Gateway host. SSH connections use your existing OpenSSH configuration and host-key verification; keep the remote Gateway bound to loopback when possible. See the remote access guide for Gateway authentication and network requirements.
Use Connection Settings in the native tray menu to edit a remote connection. Opening settings reads only the saved address and transport settings; it does not resolve credentials, and token and password fields stay empty. Retry reconnects to the saved remote Gateway with freshly resolved credentials without rewriting configuration or installing or starting a local service. Opening the remote dashboard does not prove Gateway availability or successful authentication; check the dashboard for HTTP errors, authentication prompts, and Gateway readiness.
Switching Gateways
Use Gateways → Manage Gateways… in the app or tray menu to save a direct URL or SSH connection. Add Gateway and Edit open a focused connection form; Back to Gateways returns to the saved list and discards unsaved changes. Choose token or password under Authentication and enter a credential only when needed. The credential starts masked; use Show credential to inspect what you entered. Switching authentication types clears the entered credential. For SSH connections, the optional TLS fingerprint is under Advanced connection settings.
Saved credentials stay in this app's system credential store and are never filled into the editor. Leave the credential field blank to retain the saved credentials for the same endpoint.
If the credential store is unavailable, the app keeps the dashboard open and shows one dismissible notice. Saved connections remain intact. Resolve the reported credential-store problem, then use Manage Gateways… → Try again to load them again.
The dashboard's profile menu switches the current window to a saved Gateway. Command-click or Control-click opens another window. The native Gateways menu opens or focuses an existing Gateway window without reloading its current page; Open … in New Window creates an independent window. Successful explicit selection is remembered across app restarts. Removing a selected Gateway returns the main window to Primary and closes that Gateway's other windows.
If a saved Gateway cannot load, its window returns to the local connection editor so you can correct the address or credentials. An edited endpoint becomes the remembered selection only after its dashboard loads successfully.
Selecting a dashboard does not change the Primary Gateway, Quick Chat, or the desktop connection. Set as Primary is a separate, confirmed action for saved token-authenticated connections. Primary reconnects leave independently selected Gateway windows alone. Connection Settings continues to edit the Primary connection. Saved Tauri connections are separate from the native macOS app's saved connections and browser sign-in sessions.
After connecting, Model Setup discovers AI access available to the selected Gateway and shows it as a choice. Discovery never imports or copies an account, and the companion never selects, tests, installs, or saves a provider until you click its action. The list includes supported installed providers and official provider plugins available from OpenClaw's managed plugin catalog. Installing a official provider plugin continues directly to that provider's authentication form without a capability approval prompt. Other plugins require capability review before installation. Successful verification may require a Gateway restart before the new model becomes available.
The custom endpoint option supports OpenAI- and Anthropic-compatible services.
For a local Gateway, it opens the canonical guided endpoint setup. For a remote
Gateway, run openclaw onboard --auth-choice custom-api-key on the Gateway host as directed by the setup
message; custom-provider secrets must be entered on their owning host. The
desktop companion does not copy remote provider secrets to this computer.
On a fresh install, setup also asks whether existing native Claude and Codex conversations should appear in OpenClaw. This is discovery only, not an import or copy. The option starts unchecked; declining disables both native session catalogs. Existing installations keep their current catalog behavior during an upgrade.
Once you choose AI access, Model Setup follows the provider's normal review and verification flow. A temporary connection loss resumes the admitted setup wizard on the same Gateway and account without repeating installation or the last answer. After a completed activation requests a restart, setup can resume verification of that same model. If an unfinished wizard is no longer available, setup shows a recovery message instead of repeating authentication automatically. Check again refreshes the current setup; if a model was saved, you can explicitly verify and use it. Gateway failures retain their detailed recovery message so setup can identify authentication, network, service, or restart problems.
For OpenAI, ChatGPT Login uses a ChatGPT or Codex subscription, while OpenAI API Key uses API billing. When the Gateway runs on another host and its browser callback is not reachable, choose ChatGPT Device Pairing from the additional sign-in options.
Updates
The companion checks the latest GitHub release shortly after launch and from Check for Updates in the tray menu. AppImage installs download and verify the signed update in place, then wait for Restart to update. Package-managed installs such as .deb stay owned by the system package manager and link to the release download page instead of replacing installed files. The macOS and Windows test builds use a separate opt-in desktop-test update channel; macOS self-updates like the AppImage build, while Windows downloads the update first and runs its installer only after Restart to update.
While a newer Gateway release waits for its Linux app, the latest release keeps the previous published Linux updater manifest. Its original version, signature, and download URL stay intact. Successful Linux publication advances that manifest without letting an older build replace a newer available update.
The shipped endpoint remains releases/latest/download/latest.json, and
package-managed installs still link to the existing release page. The
linux-stable publication channel does not change those client defaults.
Changing them requires separate release-owner approval and signed
installed-client migration proof.
Desktop sharing
Settings → This computer → Desktop sharing controls this companion's desktop
viewer on Linux and Windows. The macOS Tauri build calls that settings page
This Mac. Sharing defaults to enabled once the local CLI is available and
its settings can be resolved. An authored desktop.host.enabled: false remains
an opt-out until you explicitly change the native setting. The native choice
is saved in the companion's existing system credential store.
The companion starts a desktop-only CLI node for the Primary Gateway, including when the settings page has never been opened. Approve its device and desktop capability requests on that Gateway when prompted. Running confirms the local sharing process is active; opening the viewer also requires approved pairing and an authenticated local Screen Sharing/VNC server. On macOS, enable System Settings → General → Sharing → Screen Sharing. Linux and Windows use an authenticated VNC server reachable on loopback. The viewer reports setup or authentication errors when you open it.
Turning sharing off or quitting the companion closes its desktop relay and joins its process tree. Changing Primary retires the old node before starting the replacement. Each logical Gateway and local config profile has its own node identity; recovery of an SSH tunnel retains that identity when its local port changes. Computer Control and Keep computer awake retain their separate settings and permissions.
The CLI remains the owner of local configuration, including $include files.
The companion reads its resolved setting and passes the canonical config path
to the node. Missing CLI support, invalid config, and failed startup appear in
Desktop sharing status with a recovery message. If an off preference cannot
be saved, sharing stops for this run and the status warns that the previous
saved choice may return after restarting the app.
Keep computer awake
Enable Keep computer awake beside Start at Login in the native tray menu to prevent idle sleep while this companion is running. It starts off and remembers your choice across restarts using the companion's existing system credential store. The checkmark shows the saved preference. If a saved request cannot be restored, the menu says Keep computer awake (inactive) and reports an error; you can still uncheck it without retrying the unavailable power service. A new enable request is saved only after the native request succeeds. Turning it off or quitting releases the request. Closing the dashboard to the tray does not release it.
Linux uses GNOME’s native session inhibitor when available, or another desktop’s xdg-desktop-portal idle inhibitor, such as KDE’s backend. A working session or portal backend that supports idle inhibition is required; a logind sleep-delay inhibitor alone is not a keep-awake implementation. Desktop idle inhibition may also keep the display from dimming and delay automatic locking. Windows and the macOS Tauri build inhibit system idle sleep without requesting that the display stay on. Manual locking, manual sleep, and lid-close behavior remain under the operating system's control. This option does not wake or unlock a computer and does not replace the Gateway's sleep preparation.
If turning the option off cannot save the preference, idle sleep is still allowed for this run, but the error warns that the saved choice may enable it again after a restart. The checked menu item is marked inactive; restore access to the credential store and uncheck it again to save the off preference.
Quick Chat widgets
Quick Chat advertises the Gateway inline-widgets capability and renders hosted show_widget results in isolated child WebViews. The parent Quick Chat WebView is the only one granted Tauri commands; widget WebViews match no capability and therefore have no IPC access. Quick Chat accepts only assistant-message widget previews under the capability-scoped /__openclaw__/canvas/documents/ route, blocks navigation away from the original document, uses nonpersistent WebViews, and keeps stable widget instances while switching among multiple previews. Connections that require a custom Gateway TLS leaf pin remain text-only because the platform WebView cannot bind that pin. Like the other native clients, Quick Chat does not expose the Control UI sendPrompt bridge.
Retrying an unchanged Quick Chat draft after a connection error reuses its original idempotency key while the Gateway and agent remain unchanged. If the Gateway confirms the turn already completed, Quick Chat attempts to recover the matching reply from bounded session history instead of resending it. Unavailable or incomplete history produces an error; further retries of that unchanged draft on the same configured Gateway only retry recovery. Widget previews can refresh access after reconnecting to the same configured Gateway, but switching Gateways prevents old previews from using the new connection's access, even after switching back to the original URL.
Installer resource
tauri.conf.json bundles the repository's canonical scripts/install-cli.sh directly as install-cli.sh. The app never keeps a forked copy. Stable, beta, and dev installs select latest, beta, and a managed Git main checkout respectively, always under ~/.openclaw.
Icons
The icon sources of truth live next to the PNGs: icons/icon.svg (transparent
claw mark, used by the tray) and icons/icon-tile.svg (claw mark on the dark
brand tile, used for the app and package icons). Regenerate the committed PNGs
with librsvg:
cd apps/linux/src-tauri/icons
rsvg-convert -w 32 --keep-aspect-ratio icon.svg -o 32x32.png
magick 32x32.png -background none -gravity center -extent 32x32 PNG32:32x32.png
rsvg-convert -w 128 -h 128 icon-tile.svg -o 128x128.png
rsvg-convert -w 256 -h 256 icon-tile.svg -o 128x128@2x.png
rsvg-convert -w 512 -h 512 icon-tile.svg -o icon.png
magick icon.png -define icon:auto-resize=256,128,64,48,32,16 icon.ico
rsvg-convert -w 36 -h 36 tray-template.svg -o tray-template.png
macOS gets its own tray asset, icons/tray-template.svg. AppKit template images
are drawn from the alpha channel alone, so a colored or edge-to-edge opaque icon
arrives in the menu bar as a featureless blob; the template source is a
silhouette with the eyes knocked back out of it. Its geometry mirrors the native
macOS app's CritterIconRenderer at rest so both clients wear the same face, and
the 36px render is the 2× backing store for the 18pt slot tray-icon scales
menu bar images into. Non-Apple platforms keep the full-color 32x32.png.
Packaging
Build a .deb and AppImage locally (the same command manual CI runs):
plugins=$(mktemp -d)
cache=$(mktemp -d)
trap 'rm -rf "$plugins" "$cache"' EXIT
export XDG_CACHE_HOME="$cache"
apps/linux/scripts/stage-appimage-gstreamer.sh "$plugins"
apps/linux/scripts/tauri-appimage-tools.sh prepare
apps/linux/scripts/tauri-appimage-tools.sh verify pre-build
export LDAI_RUNTIME_FILE="$(apps/linux/scripts/tauri-appimage-tools.sh runtime-path)"
(
cd apps/linux/src-tauri
GSTREAMER_PLUGINS_DIR="$plugins" \
pnpm dlx @tauri-apps/cli@2.11.4 build --bundles deb,appimage \
--config '{"bundle":{"createUpdaterArtifacts":false,"useLocalToolsDir":false}}'
)
apps/linux/scripts/finalize-appimage.sh \
apps/linux/src-tauri/target/release/bundle/appimage
Bundles land in target/release/bundle/{deb,appimage}/.
The Linux App workflow checks affected pull requests with Rust formatting,
cargo test --locked --all-targets on Linux and macOS, and the packaged runtime
ABI scanner's unit tests. It also runs the native Linux inline browser smoke
under Xvfb, including pointer input, snapshots, dashboard replacement, and native
save/cancel, and uploads the synthetic screenshots and JSON results as the
linux-inline-browser proof artifact. Bundles, the full graphical first-run
scenarios, and AppImage runtime checks remain manual dispatch checks.
Manually dispatch Linux App on the branch to validate packaging before a
release. It retains all pull-request checks, builds the .deb and AppImage,
runs both native first-run cases and the packaged AppImage runtime smoke, and
uploads the bundles as the openclaw-linux-companion workflow artifact. This
validation does not publish a release.
Releases
Regular stable publication automatically requests Linux bundles after the
GitHub release becomes visible. OpenClaw Release Publish and OpenClaw Release Button both use the same Linux release owner; the request can finish before
the build, signing, and publication do. Their summaries report Linux as pending
until its own assets verify. Beta and alpha prereleases, and extended-stable
publication, do not request Linux bundles.
For independent recovery, manually dispatch Linux App Release Request from main. Provide the existing
stable release tag in tag; prerelease tags are rejected because their semver
suffix breaks Debian upgrade ordering. Enable the optional
desktop-test-bundles input only when unsigned macOS and Windows test bundles
are needed.
A successful request automatically triggers Linux App Release. It builds from
the validated release tag SHA and attaches the bundles to that tag's GitHub
release with a SHA256SUMS.linux-app.txt checksum file. The tag commit must be
reachable from main or its matching release/YYYY.M.PATCH branch; numeric
correction tags use the base version's release branch.
Linux release requests run one at a time. Default Linux-only retries verify and reuse an existing complete AppImage, Debian package, signed updater manifest, and checksum set. Partial or mismatched existing assets require targeted publication recovery; the workflow does not rebuild or overwrite them. An optional desktop-test run also refuses to replace published Linux bytes, so recover missing desktop assets separately when Linux has already published.
The publication helper records an immutable OpenClaw-<version>-linux.json
beside the bundles, then advances the fixed linux-stable channel and mirrors
it to the latest Gateway release. Reusing complete public bundles still runs
unfinished channel publication; it does not rebuild or replace those bundles.
The control release is prerelease/non-latest and requires explicit
initialization by an authorized Linux publication, never by ordinary PR validation.
Core finalization remains independent of Linux readiness. After finalization, a detached mirror-only request catches up the legacy endpoint. A dispatch is not a successful mirror: cancellation, queue overflow, timeout, or readback failure leaves a visible degraded result for reconciliation. See the Linux publication contract.
The website selects desktop assets at build time. After publication, rebuild
openclaw.ai through its existing deployment owner and verify the deployed Apps
card's Linux version and both download links.