forked from bots-garden/ori
| 🛟 Updated. | 1 | # How to build ori-desktop |
| 2 | ||
| 3 | This guide shows how to build the [ori-desktop](./README.md) Wails shell on each platform, and | |
| 4 | what to watch out for. See [README.md](./README.md) for what the app does and | |
| 5 | [README.fr.md](./README.fr.md) for the French version of that overview. | |
| 6 | ||
| 7 | ## Prerequisites (every platform) | |
| 8 | ||
| 9 | - **Go 1.25 or newer** — `go.mod` requires `go 1.25.0`. | |
| 10 | - **The Wails v2 CLI**, matching the module's Wails version: | |
| 11 | ||
| 12 | ```bash | |
| 13 | go install github.com/wailsapp/wails/v2/cmd/wails@v2.16.0 | |
| 14 | export PATH="$PATH:$(go env GOPATH)/bin" | |
| 15 | wails version # → v2.16.0 | |
| 16 | ``` | |
| 17 | ||
| 18 | - **No Node or npm.** The frontend is plain HTML/CSS/JS embedded as-is; `wails.json` leaves | |
| 19 | `frontend:install` and `frontend:build` empty on purpose. | |
| 20 | ||
| 21 | Everything below is run from the `ori-desktop/` directory, which is a **separate Go module** | |
| 22 | (`rickub.com/bots-garden/ori-desktop`). The repository root's `make build` and `go test ./...` | |
| 23 | never touch it. | |
| 24 | ||
| 25 | ## What can be built from where | |
| 26 | ||
| 27 | Wails compiles the native window through cgo against the platform's webview, so the host decides | |
| 28 | what is reachable: | |
| 29 | ||
| 30 | | Target | From macOS | From Linux | From Windows | | |
| 31 | | --- | --- | --- | --- | | |
| 32 | | `darwin/*` (`.app`) | ✅ | ❌ needs the macOS SDK | ❌ | | |
| 33 | | `linux/*` | ❌ | ✅ | ❌ | | |
| 34 | | `windows/*` (`.exe`) | ✅ | ✅ | ✅ | | |
| 35 | ||
| 36 | Windows is the only free cross-build: WebView2 is loaded at runtime, so no C toolchain is | |
| 37 | involved. macOS needs Cocoa and WKWebView from Xcode, and Linux needs WebKitGTK — neither is | |
| 38 | cross-compilable in practice. | |
| 39 | ||
| 40 | All outputs land in `build/bin/` and can coexist there, since each target has a distinct name: | |
| 41 | `ori-desktop` (Linux), `ori-desktop.app` (macOS), `ori-desktop.exe` (Windows). | |
| 42 | ||
| 43 | ## macOS | |
| 44 | ||
| 45 | 1. Install the Xcode command line tools, if they are not already there: | |
| 46 | ||
| 47 | ```bash | |
| 48 | xcode-select --install | |
| 49 | ``` | |
| 50 | ||
| 51 | 2. Build and launch: | |
| 52 | ||
| 53 | ```bash | |
| 54 | cd ori-desktop | |
| 55 | wails build | |
| 56 | xattr -cr build/bin/ori-desktop.app # clear the quarantine attribute | |
| 57 | open build/bin/ori-desktop.app | |
| 58 | ``` | |
| 59 | ||
| 60 | No build tag is needed: `-tags webkit2_41` is a Linux-only concern (see below). | |
| 61 | ||
| 62 | 3. The app opens on its connection screen and needs an ori server to reach. From the repository | |
| 63 | root: `make run` (Claude Code) or `make run-mock` (demo agent, no network). The | |
| 64 | `scripts/launch-ori.applescript` launcher does the whole sequence — start the sandbox, wait | |
| 65 | for `/healthz`, open the `.app`. | |
| 66 | ||
| 67 | ### Choosing the architecture | |
| 68 | ||
| 69 | `wails build` alone targets the architecture of the machine you build on. To be explicit: | |
| 70 | ||
| 71 | ```bash | |
| 72 | wails build -platform darwin/universal # one .app running on Apple Silicon and Intel | |
| 73 | wails build -platform darwin/arm64 # Apple Silicon only | |
| 74 | wails build -platform darwin/amd64 # Intel only | |
| 75 | ``` | |
| 76 | ||
| 77 | A `universal` build runs the Go compiler twice and merges the results with `lipo`, so it takes | |
| 78 | about twice as long and produces a noticeably larger bundle. | |
| 79 | ||
| 80 | ### Bundle details | |
| 81 | ||
| 82 | `build/darwin/Info.plist` is a Go template filled from the `info` block of `wails.json` | |
| 83 | (product name `ori`, version `0.1.0`, company `bots-garden`). It sets | |
| 84 | `NSAppTransportSecurity/NSAllowsLocalNetworking` so App Transport Security allows the app to load | |
| 85 | ori over plain HTTP on the loopback interface — without it the iframe stays blank. | |
| 86 | `build/darwin/Info.dev.plist` is the variant `wails dev` uses. | |
| 87 | ||
| 88 | ## Linux | |
| 89 | ||
| 90 | 1. Install the GUI toolchain. On Ubuntu 26.04 (and any distribution that has moved past | |
| 91 | WebKitGTK 4.0): | |
| 92 | ||
| 93 | ```bash | |
| 94 | sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev | |
| 95 | ``` | |
| 96 | ||
| 97 | 2. Build with the matching build tag: | |
| 98 | ||
| 99 | ```bash | |
| 100 | cd ori-desktop | |
| 101 | wails build -tags webkit2_41 | |
| 102 | ``` | |
| 103 | ||
| 104 | **The build tag is mandatory on any system without WebKitGTK 4.0.** Wails' default cgo | |
| 105 | `pkg-config` line asks for `webkit2gtk-4.0`; where only 4.1 is packaged, a bare `wails build` | |
| 106 | stops with: | |
| 107 | ||
| 108 | ``` | |
| 109 | # [pkg-config --cflags -- gtk+-3.0 gio-unix-2.0 webkit2gtk-4.0 …] | |
| 110 | Package 'webkit2gtk-4.0' not found | |
| 111 | ``` | |
| 112 | ||
| 113 | `-tags webkit2_41` switches Wails to the `webkit2gtk-4.1` pkg-config name. On an older | |
| 114 | distribution that still ships `libwebkit2gtk-4.0-dev`, drop the tag. | |
| 115 | ||
| 116 | Two traps: | |
| 117 | ||
| 118 | - **`wails doctor` reports a false negative.** It probes `webkit2gtk-4.0` only, so even with 4.1 | |
| 119 | correctly installed it prints `libwebkit | Unknown | Not Found` and | |
| 120 | `Fatal: Required dependencies missing: libwebkit`. Ignore it and check the real thing: | |
| 121 | ||
| 122 | ```bash | |
| 123 | pkg-config --modversion gtk+-3.0 webkit2gtk-4.1 | |
| 124 | ``` | |
| 125 | ||
| 126 | - **`make desktop` runs a bare `wails build`**, so it fails on those distributions. Build from | |
| 127 | `ori-desktop/` with the tag instead. The target is correct on macOS, where it is normally used. | |
| 128 | ||
| 129 | ## Windows | |
| 130 | ||
| 131 | Cross-build from anywhere, no C toolchain required: | |
| 132 | ||
| 133 | ```bash | |
| 134 | cd ori-desktop | |
| 135 | wails build -platform windows/amd64 # → build/bin/ori-desktop.exe | |
| 136 | wails build -platform windows/arm64 | |
| 137 | ``` | |
| 138 | ||
| 139 | The resulting binary needs the WebView2 runtime, which is preinstalled on Windows 10 and 11. The | |
| 140 | `-webview2` flag picks the strategy for machines without it (`download`, the default, `embed`, | |
| 141 | `browser` or `error`), and `-nsis` produces an installer — that one needs NSIS on the build | |
| 142 | machine (`sudo apt-get install nsis` on Debian-family systems). | |
| 143 | ||
| 144 | `build/windows/` holds the manifest, icon and NSIS assets. | |
| 145 | ||
| 146 | ## Useful flags | |
| 147 | ||
| 148 | `wails build -help` lists them all; these are the ones that matter here. | |
| 149 | ||
| 150 | | Flag | Use | | |
| 151 | | --- | --- | | |
| 152 | | `-clean` | Empties `build/bin/` first. **It removes the other platforms' outputs too** — the `.app`, the `.exe` and the Linux binary all live in that one directory. | | |
| 153 | | `-platform os/arch` | Target something other than the host; comma-separate several. Defaults to the host. | | |
| 154 | | `-tags "…"` | Go build tags — this is how `webkit2_41` is passed. | | |
| 155 | | `-dryrun` | Prints the `go build` command Wails would run, without running it. Handy for diagnosing a cgo or pkg-config failure. | | |
| 156 | | `-debug` / `-devtools` | Keep the webview devtools available in a production build. | | |
| 157 | | `-race`, `-trimpath`, `-ldflags`, `-o` | Passed through to the Go compiler / output name. | | |
| 158 | | `-s` | Skip the frontend step — a no-op here, since there is no frontend build. | | |
| 159 | ||
| 160 | `wails build` also regenerates `frontend/wailsjs/` (the typed JS wrappers for the bound Go | |
| 161 | methods). Nothing imports them and they are gitignored; the frontend calls | |
| 162 | `window.go.main.App.<Method>()` directly. | |
| 163 | ||
| 164 | ## Development mode | |
| 165 | ||
| 166 | ```bash | |
| 167 | cd ori-desktop | |
| 168 | wails dev # add -tags webkit2_41 on Linux, as for build | |
| 169 | ``` | |
| 170 | ||
| 171 | This opens the window and reloads it whenever a file under `frontend/src/` changes (`assetdir` in | |
| 172 | `wails.json`). It also serves the app on http://localhost:34115, so it can be opened in a normal | |
| 173 | browser with devtools while still calling the Go methods. | |
| 174 | ||
| 175 | ## Tests | |
| 176 | ||
| 177 | The connection logic is pure Go and needs no GUI dependency at all — it can be run on a machine | |
| 178 | where the build itself is impossible: | |
| 179 | ||
| 180 | ```bash | |
| 181 | cd ori-desktop && go test ./internal/... | |
| 182 | # or, from the repository root: | |
| 183 | make desktop-test | |
| 184 | ``` | |
| 185 | ||
| 186 | ## Troubleshooting | |
| 187 | ||
| 188 | **`Package 'webkit2gtk-4.0' not found` (Linux)** — add `-tags webkit2_41`; see above. | |
| 189 | ||
| 190 | **`wails: command not found`** — `$(go env GOPATH)/bin` is not on `PATH`. | |
| 191 | ||
| 192 | **macOS refuses to open the `.app`** — two distinct causes: | |
| 193 | ||
| 194 | - *"cannot be opened"* / nothing happens: the executable inside the bundle lost its execute bit. | |
| 195 | This happens when `build/bin/` sits in a cloud-synced folder (iCloud Drive, kDrive, Dropbox), | |
| 196 | which does not always preserve POSIX modes. Restore it with: | |
| 197 | ||
| 198 | ```bash | |
| 199 | chmod +x build/bin/ori-desktop.app/Contents/MacOS/ori-desktop | |
| 200 | ``` | |
| 201 | ||
| 202 | That invalidates the bundle's signature, so if macOS then calls the app damaged, rebuild with | |
| 203 | `wails build -clean`. | |
| 204 | ||
| 205 | - *"cannot be opened because it is from an unidentified developer"* / *"damaged"*: Gatekeeper. | |
| 206 | `xattr -cr build/bin/ori-desktop.app` clears the quarantine flag on the machine that built it. | |
| 207 | Wails only signs the bundle ad hoc, so distributing it to other Macs requires a Developer ID | |
| 208 | certificate, `codesign` and notarisation with `notarytool`. | |
| 209 | ||
| 210 | **The window opens but stays empty** — that is the connection screen failing to reach ori, not a | |
| 211 | build problem. Check that an ori server answers on the URL shown (`curl http://localhost:8888/healthz`) | |
| 212 | and use the "Open in browser" button to confirm. | |
| 213 | ||
| 214 | ## See also | |
| 215 | ||
| 216 | - What the app is and how it talks to ori: [README.md](./README.md) / [README.fr.md](./README.fr.md) | |
| 217 | - Running the ori server itself: the repository's [quickstart](../quickstart.md) | |
| 218 | - Running the test suites: [docs/en/how-to/run-the-tests.md](../docs/en/how-to/run-the-tests.md) |