# OpenClaw for Linux

The Linux companion is a Tauri v2 desktop shell for OpenClaw Gateways. It discovers nearby Gateways over Bonjour, installs the CLI when needed, delegates local Gateway service management to `openclaw gateway`, opens the selected Gateway's Control UI, and stays available in the system tray.

## Linux prerequisites

Debian and Ubuntu development packages:

```bash
sudo apt update
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \
  libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
```

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 available on its Ubuntu build host. For a source build or when
rebuilding either Linux bundle, install the packages explicitly:

```bash
sudo apt update && sudo apt install gstreamer1.0-libav gstreamer1.0-plugins-good gstreamer1.0-plugins-bad
```

The released AppImage therefore carries the codecs installed by the release
workflow instead of relying on GStreamer packages from the user's system.

## Develop and build

The companion frontend is static HTML, CSS, and JavaScript. The shared Canvas A2UI renderer is
generated from the Canvas plugin, so install repository dependencies once before building:

```bash
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 first run, release builds automatically install the stable CLI channel, while development builds ask for a release channel and preselect Development. After the CLI install, the app opens the local dashboard once with onboarding mode enabled. Reconnects and later app launches use the normal dashboard URL.

## 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**.

## Canvas bridge

The running app gives the headless `openclaw node run` host a single Canvas WebView. The bundled `linux-canvas` plugin advertises `canvas.*` only while the app socket exists. The app listens at `$XDG_RUNTIME_DIR/openclaw-canvas.sock` (or `/tmp/openclaw-canvas-$UID.sock`) with mode `0600`; a headless Linux node without the app does not advertise Canvas.

The Canvas plugin sources remain the source of truth for the A2UI renderer. Each native build
generates `index.html` and `a2ui.bundle.js` into its isolated build output before compiling. Run
`node scripts/sync-native-a2ui.mjs --check` from the repository root to verify fresh bundles are
byte-identical and every native build owner is wired.

## 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 Canvas 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.

## 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:

```bash
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 CI runs):

```bash
cd apps/linux/src-tauri
pnpm dlx @tauri-apps/cli@2.11.4 build --bundles deb,appimage
```

Bundles land in `target/release/bundle/{deb,appimage}/`. The `Linux App` CI
workflow uploads them as the `openclaw-linux-companion` artifact on pull
requests touching `apps/linux/**` and on manual dispatch.

## Releases

The `Linux App Release` workflow (manual dispatch, release operators) builds
the bundles from an existing stable release tag (prerelease tags are
rejected: their semver suffix breaks Debian upgrade ordering) and attaches them to that tag's
GitHub release with a `SHA256SUMS.linux-app.txt` checksum file. It refuses
tags whose commit is not reachable from `main`: Linux bundles ship for
main-based releases only.
