guides

Grain Desktop (optional GUI)

Wails-based operator console — thin client of the grain daemon for macOS and Linux.

Grain Desktop is an optional GUI for local (and remote) grain sandboxes. It is a thin client of the same control-plane API as the CLI and SDKs — not a second engine, and not Electron.

What you get

AreaNotes
SandboxesList with search/sort/compact density, create, start/stop/remove, multi-select bulk actions, right-side inspector
InspectorOverview (agent badge, metrics charts) · Shell · Logs — in-app shell plus open in new window; More → Export as recipe… / Save as library recipe / Promote to golden + fill pool
Agent honestyWhile a golden is still booting, failed agent health shows checking… (not “not installed”) until success or a short grace after create
ImagesCatalog ready/missing, pull with progress
RecipesLocal library (~/.grain/recipes), New from form…, import file/URL (preview→add), official catalog, YAML edit (valid-only save), Deploy… with preflight. Import never auto-creates a VM.
MCPStatus, enable in config, copy IDE snippets, ensure-running (local)
DoctorHost tool + daemon checks with fix hints
SettingsPreferences, Warm pool (template / size / running mode + Fill), hosts, Advanced config.yaml (strict validate)
ActivityToasts + drawer for all clients (CLI/MCP/API/Desktop via daemon GET /activity); optional source filter; persisted across daemon restarts
HostsTop-bar switcher; remote profiles never start a remote engine
Fast createNew: cold / from template / from warm pool (prefers pool when ready > 0; honest empty/unconfigured copy)
Bulk StartConfirm dialog + progress; preflight against active host caps from GET /info (blocks over-cap)
Multi-RunMulti-select Run… — progressive results, re-run failed, copy all (stdout+stderr)

Install / launch

From this repository (developers)

bash
go install github.com/wailsapp/wails/v2/cmd/wails@latest
wails doctor

# from repo root
just desktop-test
just desktop-build
./bin/grain-desktop            # launcher → Grain.app on macOS (not ./bin/Grain — collides with CLI on case-insensitive volumes)
open desktop/build/bin/Grain.app

Requires CGO and the OS webview (WKWebView on macOS, WebKitGTK on Linux). See desktop/README.md.

Installer flag

bash
# CLI + Desktop attempt
curl -fsSL https://raw.githubusercontent.com/cxdy/grain/main/scripts/install.sh | bash -s -- --desktop

# or from a checkout
./scripts/install.sh --desktop

From v0.8.0 onward, GitHub Releases attach Desktop assets built by the Release Desktop workflow:

PlatformAssetInstall location
macOSGrain_darwin_<arch>.app.tar.gz~/Applications/Grain.app (+ optional grain-desktop launcher)
Linuxgrain-desktop_linux_<arch>.tar.gz~/.local/bin/grain-desktop (or GRAIN_INSTALL_DIR)

install.sh --desktop prefers those assets. If missing (or offline), it builds from source in a checkout with just + Wails; otherwise it prints build instructions (non-fatal when the CLI still installs).

Linux

bash
# WebKitGTK 4.1 (Ubuntu 22.04+ / 24.04 / 26.04 — no 4.0 package)
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev
just desktop-build          # uses -tags webkit2_41; no codesign
./bin/grain-desktop-bin     # or ./bin/grain-desktop
grain up                    # daemon must be up for list/create

just desktop-build on Linux skips macOS codesign/ditto/sips and builds with -tags webkit2_41 -nopackage.

If the window paints but nothing is clickable: rebuild after the Linux fixes (splash no longer blocks the UI; Wails bindings resolve lazily). Run from a terminal and check for JS/console errors; start the daemon with grain up first.

UI map

text
Host ▾ · health · Activity · Doctor · Docs
Sandboxes | Images | Recipes | Settings
[ list .................. ] [ inspector: Overview | Shell | Logs ]
  • Shell focuses the in-app terminal; opens a second Grain window (--shell). Keyboard input goes through live Wails ShellWrite bindings.
  • Start and Stop never appear together.
  • Sandbox list: search by name/image/status; sort; compact density; always scrollable.
  • Header Refresh reloads the current view only.
  • Click a toast to open Activity for that event.
  • Theme toggle respects light/dark; native title bar and scrollbars follow the theme.

Config

Desktop reads ~/.grain/config.yaml (same file as the CLI). Optional keys:

yaml
connections:
  - name: local
  - name: lab
    api: http://127.0.0.1:7474
    token_env: GRAIN_TOKEN_LAB

desktop:
  default_connection: local
  start_local_daemon: true

Settings → Advanced edits YAML with strict unknown-key validation and a trailing newline. Saving may restart the local daemon.

Warm pool (Settings + New)

ControlAction
Settings → Warm poolSet template, desired size (0 disables), optional running mode → Apply warm pool (writes config + restarts local daemon) → Fill pool
More → Promote to golden + fill poolSuspend if running, set template to that sandbox, fill
New sandboxPrefers From warm pool when ready > 0; empty/unconfigured copy stays honest (no silent cold while implying pool is ready)
Bulk StartPreflight against active host caps from GET /info (blocks over max_vms / CPU / memory when known)
ActivityFilter by desktop / cli / mcp / api

See lifecycle — fast create.

Multi-host Run

Select two or more sandboxes → Run…. Results stream per host (hostname highlighted). After a run:

ControlBehavior
Re-run failedRe-executes only hosts that had an error or non-zero exit
Copy allClipboard export with per-host stdout/stderr blocks

Activity feed

  • Merges daemon events (GET /activity, all clients) with local UI notes.
  • Persisted on the daemon host at data_dir/activity.json.
  • Filter dropdown: All · Desktop · CLI · MCP · API/SDK.
  • Clients should send X-Grain-Client: desktop|cli|mcp|sdk (Desktop does this automatically).

Metrics charts

When sandbox metrics are enabled (default), Overview shows guest history from the host-side ring. See Metrics.

Sandbox disk increases run qemu-img resize when the sandbox is stopped (refuses while running). Grow the guest filesystem separately after resize.

Security

Same single-operator model as the CLI: whoever holds the unix socket or API token has full control. Prefer token_env. Cleartext remote HTTP is warned.

Relationship to CLI / MCP

SurfaceRole
CLIPrimary automation and scripts
MCPCoding-agent tools (grain up --mcp / grain mcp)
DesktopSituational awareness + lifecycle + attach

Headless installs stay CLI-only; Desktop is optional.