CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
apps/desktop is the web client in a native window. It embeds the same build warp-web does and serves it through the same Go package, so every screen is shared. Unlike warp-web it proxies nothing: the client calls the homeserver directly, and the CSP allows the homeserver plus any https: and wss: origin for the call backend. - First run asks for the homeserver: a server name or address, with .well-known discovery and a /versions check; File > Change homeserver asks again. Signed-in sessions keep their own base URL, so a change never sends one server's token to another. - Links to other sites open in the system browser (/_desktop/links.js, added to index.html); only http, https and mailto are opened. - One instance at a time, since sessions and keys live in the webview's storage. - Dev builds open the DevTools Protocol on Windows when WARP_DESKTOP_REMOTE_DEBUGGING_PORT is set, for scripted testing. - Packaging: icon, version info and manifest in the Windows exe, a macOS .app with camera and microphone descriptions, Linux packages via nfpm. Make targets: desktop, desktop-run, desktop-test, desktop-resources, desktop-macos, desktop-linux. Web client: host and client move out of internal/ so the desktop app can import them, and host gains AnyCallOrigin. The Dockerfile, .dockerignore and the vite output path follow the move. Pinned to Wails v3.0.0-beta.27. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
146 lines
7.3 KiB
Markdown
146 lines
7.3 KiB
Markdown
# Warp desktop client
|
||
|
||
The [web client](../web/README.md) in a native window, built with
|
||
[Wails v3](https://v3alpha.wails.io). Every screen is the web client's:
|
||
`warp-desktop` embeds the same build `warp-web` does and serves it through
|
||
the same Go package (`apps/web/host`), so web and desktop don't drift
|
||
apart. It runs on Windows (WebView2), macOS (WKWebView) and Linux
|
||
(WebKitGTK).
|
||
|
||
```
|
||
window ──► wails.localhost ──► shell (this app) ── the web client, /config.json
|
||
│ first-run page, links
|
||
└──────────────────────────────────────────────► homeserver /_matrix/*
|
||
```
|
||
|
||
Unlike `warp-web`, the desktop app isn't installed next to one homeserver,
|
||
so it proxies nothing. The client calls the homeserver directly, the way
|
||
any Matrix client does; homeservers answer CORS for every origin. The
|
||
Content-Security-Policy allows the homeserver plus any `https:` and `wss:`
|
||
origin, because the call backend (the LiveKit JWT service and SFU) is
|
||
learned from the homeserver at run time and can't be listed in advance.
|
||
|
||
## What it adds to the web client
|
||
|
||
- **First run asks for the homeserver.** A server name (`example.org`) or
|
||
an address. Discovery follows `/.well-known/matrix/client` and checks
|
||
`/_matrix/client/versions`. If the well-known document names an address
|
||
that doesn't answer, the typed address is used when that one works.
|
||
**File → Change homeserver…** asks again. A session already signed in
|
||
keeps the server it signed in to until you sign out, so changing the
|
||
homeserver never sends one server's access token to another.
|
||
- **Links to other sites open in the system browser.** That covers a URL in
|
||
a message, `target="_blank"` and `window.open`. Without this they would
|
||
replace the app in its window or open a bare webview window.
|
||
`/_desktop/links.js` does it; the shell adds a `<script>` tag for it to
|
||
`index.html`. Only `http`, `https` and `mailto` URLs are opened.
|
||
- **One instance at a time.** Sessions and encryption keys live in the
|
||
webview's storage, and two instances on one store would both sync and
|
||
use the same one-time keys. Starting the app again brings the open window
|
||
forward.
|
||
|
||
## Where things are kept
|
||
|
||
| What | Where |
|
||
|---|---|
|
||
| The chosen homeserver | `desktop.json` in the user config directory, under `Warp` (`%AppData%\Warp` on Windows, `~/Library/Application Support/Warp` on macOS, `~/.config/Warp` on Linux) |
|
||
| Sessions, encryption keys, cache | the webview's storage: `%LocalAppData%\Warp\WebView2` on Windows; the platform webview's default location elsewhere |
|
||
|
||
Signing out deletes a session's keys, the same as in the browser (see
|
||
[Encryption keys in the browser](../web/README.md#encryption-keys-in-the-browser)).
|
||
|
||
## Build and run
|
||
|
||
Requires Go 1.26, Node 22 and pnpm. On Windows the WebView2 runtime, which
|
||
Windows 11 ships with, and no C compiler. On macOS, Xcode's command line
|
||
tools. On Linux, a C compiler with `libgtk-4-dev` and `libwebkitgtk-6.0-dev`
|
||
(Wails needs cgo there, and builds against GTK 4 by default).
|
||
|
||
```bash
|
||
pnpm install
|
||
make desktop # builds the web client, then bin/warp-desktop
|
||
./bin/warp-desktop
|
||
```
|
||
|
||
| Flag | Environment | |
|
||
|---|---|---|
|
||
| `-homeserver` | `WARP_DESKTOP_HOMESERVER` | use this homeserver for this run without saving it |
|
||
| `-version` | | print the version |
|
||
|
||
| Command | What |
|
||
|---|---|
|
||
| `make desktop` | a release build: `-tags production` (no developer tools), and on Windows a GUI program with no console |
|
||
| `make desktop-run` | build the web client and run the app with the developer tools (View → Open Developer Tools) |
|
||
| `make desktop-test` | vet and test the Go code |
|
||
| `make desktop-macos` | on macOS: `bin/Warp.app` |
|
||
| `make desktop-linux` | on Linux: `bin/warp-desktop.deb`, `.rpm` and `.pkg.tar.zst` |
|
||
| `make desktop-resources` | regenerate the icons and the Windows `.syso` files |
|
||
|
||
A development build (one without `-tags production`) also opens the Chrome
|
||
DevTools Protocol when `WARP_DESKTOP_REMOTE_DEBUGGING_PORT` is set, on
|
||
Windows. A script or Playwright can then drive the real window:
|
||
|
||
```bash
|
||
WARP_DESKTOP_REMOTE_DEBUGGING_PORT=9229 go run ./cmd/warp-desktop
|
||
```
|
||
|
||
## Packaging
|
||
|
||
The inputs are in `build/`. The `wails3` CLI does the generating and the
|
||
Linux packaging; the Makefile runs it with `go run` at the version
|
||
`go.mod` pins (`v3.0.0-beta.27`), so it needs no install. `DESKTOP_VERSION`
|
||
in the Makefile (default `0.1.0`) is the version the OS sees in each
|
||
package; `-version` prints the build's git version.
|
||
|
||
- **Windows.** `cmd/warp-desktop/rsrc_windows_{amd64,arm64}.syso` carry the
|
||
icon, the version info and the application manifest (per-monitor DPI,
|
||
common controls 6, `asInvoker`). They are committed, so `make desktop`
|
||
(and a plain `go build`) links them in with no extra step. The icon,
|
||
`build/windows/icon.ico`, takes 16–48 px from the brand favicon (the
|
||
symbol's small cut) and 64–256 px from the app icon tile;
|
||
`build/windows/mkico.go` merges the two. After changing the icon,
|
||
`build/windows/info.json`, the manifest or `DESKTOP_VERSION`, run
|
||
`make desktop-resources` and commit the `.syso` files.
|
||
- **macOS.** `make desktop-macos`, on a Mac, builds the binary and puts it
|
||
in `bin/Warp.app` with `build/darwin/Info.plist` and `icons.icns`, then
|
||
signs the bundle ad hoc. The `Info.plist` has `NSCameraUsageDescription`
|
||
and `NSMicrophoneUsageDescription`: without them macOS ends the app the
|
||
moment a call or the QR scanner asks for the camera or microphone. The
|
||
bundle is for the CPU it was built on, and ad-hoc signed it opens only on
|
||
the machine that built it; to hand it out, sign it with a Developer ID
|
||
and notarize it.
|
||
- **Linux.** `make desktop-linux`, on Linux, builds the binary and turns it
|
||
into `.deb`, `.rpm` and Arch packages with nfpm (through `wails3 tool
|
||
package`, configured by `build/linux/nfpm.yaml`). They install
|
||
`/usr/bin/warp-desktop`, a menu entry and the icon, and depend on GTK 4
|
||
and WebKitGTK 6.0 (Ubuntu 24.04+, Debian 13+, Fedora 40+).
|
||
`DESKTOP_FORMATS=deb` builds one format; `DESKTOP_MAINTAINER` defaults
|
||
to your git name and email.
|
||
|
||
`build/appicon.png` and `build/windows/favicon.ico` are copies from the
|
||
brand kit (`DESIGN/warp-brand/logo-kit`, not in git):
|
||
`symbol/warp-symbol-app-icon-1024.png` and `web/favicon.ico`.
|
||
|
||
## Layout
|
||
|
||
| Path | What |
|
||
|---|---|
|
||
| `cmd/warp-desktop/` | the binary: the Wails app, window, menu and single-instance lock |
|
||
| `internal/shell/` | the webview's `http.Handler`: the client through `apps/web/host`, the first-run page and discovery, the settings file, links |
|
||
| `build/` | packaging inputs: icons, the Windows manifest and version info, `Info.plist`, the nfpm config |
|
||
|
||
## Not yet
|
||
|
||
These follow from [PLAN.md §8.3](../../PLAN.md):
|
||
|
||
- Installers and signing: a Windows installer (NSIS or MSIX) and a signed
|
||
executable, a universal (arm64 + amd64), Developer ID signed and
|
||
notarized macOS `.app` in a `.dmg`, an AppImage or Flatpak. `wails3`
|
||
has tasks for most of these. None of the packages above is built in CI
|
||
yet.
|
||
- Native notifications, a tray icon, auto-update.
|
||
- Sync and encryption in Go (`mautrix-go`) behind the same Pinia stores,
|
||
with the access token in the OS keychain. Today the desktop app runs
|
||
matrix-js-sdk in the webview exactly as the browser does. Whether to move
|
||
this to Go is open question 5 in the plan.
|