Read when:
- adding
--desktop,--browser, or--codeto a workflow; - choosing a Linux desktop environment with
--desktop-env; - changing how Crabbox detects whether a lease can host a visible desktop;
- adding a new lease capability flag.
Lease capabilities are opt-in features that extend what a runner can do beyond
running headless commands. They are distinct from the provider feature set
declared in ProviderSpec.Features: a feature set says "this provider can
host a desktop"; a capability label says "this lease was created with a
desktop and exposes one right now".
--desktop visible desktop with a loopback VNC server (XFCE, Wayland, or GNOME)
--browser Chrome/Chromium installed and exported via $BROWSER and $CHROME_BIN
--code code-server bound to a loopback port for the portal code bridge
All three default to off. They must be requested when the lease is created
(crabbox warmup --desktop) and are then reused on later commands. A lease
created without a capability cannot grow it later; warm a new lease instead.
The desktop flavor is selected with --desktop-env xfce|wayland|gnome
(default xfce). Wayland and GNOME require --target linux.
Capability flags follow a two-step validation, both in
internal/cli/capabilities.go.
- Provider feature check (
validateRequestedCapabilities). When you set a capability flag, Crabbox looks up the selected provider'sSpec().Featuresand rejects the request if the matching feature (FeatureDesktop,FeatureBrowser,FeatureCode) is missing. Hetzner Linux supports all three; the delegated-run providers support none. Additional guards:--codeis restricted to managed Linux leases; Windows, macOS, and static SSH are rejected.--target windows --windows-mode wsl2rejects--desktop(use--windows-mode normalfor a desktop, or omit--desktopfor WSL2).provider=azure --target windowssupports SSH, sync, run, and desktop/VNC only;--browser,--code, and--tailscaleneed Linux or AWS Windows.--desktop-env wayland|gnomerequires--target linux.
- Lease label check (
enforceManagedLeaseCapabilities). When you reuse a lease with--id, Crabbox checks the matching label (desktop=true,browser=true,code=true) on the existing record. If the label is missing, it refuses with a hint to warm a new lease. A non-default--desktop-envmust also match the lease's storeddesktop_envlabel.
Label enforcement is skipped for static SSH targets, because Crabbox does not
own the host. There the capability is detected probe-by-probe instead (see
Static targets). A macOS lease is treated as
desktop-capable without a desktop=true label, because Screen Sharing is the
desktop.
When a managed Linux lease is created with --desktop (default xfce),
bootstrap (internal/cli/bootstrap.go) installs and enables systemd units for:
- Xvfb on display
:99; - an XFCE4 session (
xfce4-session, panel, terminal, settings, theme); - x11vnc bound to
127.0.0.1:5900with-localhost; - a randomized VNC password at
/var/lib/crabbox/vnc.password; - screenshot and capture tooling:
scrot,ffmpeg, plus input helpers (xdotool,wmctrl,xclip,xsel).
With --desktop-env wayland or gnome, the lease runs a Wayland compositor
(labwc) with WayVNC on the same loopback 127.0.0.1:5900.
crabbox vnc --id ... opens an SSH tunnel to that loopback port; your local
VNC viewer connects through the tunnel using the password the CLI reads from
the lease. There is no public VNC port — the loopback bind is the security
boundary.
The VNC password lives at an OS-specific path:
/var/lib/crabbox/vnc.password # Linux
/var/db/crabbox/vnc.password # macOS
C:\ProgramData\crabbox\vnc.password # Windows
When a run injects environment for a desktop lease, Crabbox probes the lease's
desktop env file and sets CRABBOX_DESKTOP=1 plus the relevant display
variables. For X11 it sets:
DISPLAY=:99
CRABBOX_DESKTOP=1
For a Wayland/GNOME desktop it instead forwards WAYLAND_DISPLAY,
XDG_RUNTIME_DIR, and related variables detected on the host. Tools that
respect these draw onto the desktop the lease created.
For per-OS detail and known limits, see:
--browser adds a usable browser to the lease without provisioning a full
desktop.
On managed Linux, bootstrap installs:
- Google Chrome stable when the repo is reachable;
- Chromium (or
chromium-browser) as a fallback; - build helpers (
build-essential,python3, etc.) so dependency installs that compile against Chromium succeed; - a managed Chrome policy and a launcher wrapper, whose path is written to
/var/lib/crabbox/browser.envasBROWSERandCHROME_BIN.
On static and macOS/Windows targets, Crabbox probes for an existing browser
(probeBrowserEnv) and aborts before the command runs if none is found:
- macOS:
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome; - Windows:
chrome.exeormsedge.exefrom PATH or the standard install directories; - Linux:
$BROWSER,$CHROME_BIN, thengoogle-chrome,chromium, orchromium-browserfrom PATH.
The resolved path is exported into the run:
BROWSER=/path/to/browser
CHROME_BIN=/path/to/browser
CRABBOX_BROWSER=1
Test runners that read BROWSER or CHROME_BIN (Vitest, Playwright, etc.)
work without extra plumbing.
For browser QA where the remote service is sensitive to source IP (login
flows, regional CDN behavior), pair --browser with
mediated egress: crabbox egress start opens a lease-local proxy
that exits through the operator machine, and crabbox desktop launch --egress
passes that proxy to Chrome.
--code provisions code-server on managed Linux leases. Bootstrap:
- installs the binary at
/usr/local/bin/code-server(standalone install,--prefix=/usr/local); - binds it to a loopback port (default
8080); - relies on coordinator state for the access token.
crabbox code --id ... and the portal open a code-server tab through the
authenticated portal bridge at /portal/leases/{id-or-slug}/code/. The bridge
proxies HTTP and WebSocket traffic to the loopback port and injects the auth
token, so you never handle it directly. There is no public code-server port.
Code is managed-Linux-only because the bridge depends on the lease shape and the cloud-init that installs the binary. Windows, macOS, and static SSH are intentionally unsupported today.
Managed lease records carry capability labels (internal/cli/provider_labels.go)
so list, status, and the portal can render the capability matrix without
re-probing the host:
desktop=true
desktop_env=xfce|wayland|gnome # only when desktop=true
browser=true
code=true
enforceManagedLeaseCapabilities reads these labels to gate --desktop,
--browser, --code, and --desktop-env on --id reuse paths. The labels
are written at lease creation and never flipped on a live lease.
Capabilities are independent — any combination is allowed where the provider supports them:
crabbox warmup --desktop # desktop only (XFCE)
crabbox warmup --desktop --desktop-env gnome # GNOME desktop
crabbox warmup --desktop --browser # browser on the desktop
crabbox warmup --desktop --browser --code # full interactive box
crabbox warmup --browser # headless browser, no VNC
crabbox warmup --code # editor-only Linux leaseCapability bootstrap adds installation time. A bare lease warms fastest; a lease with all three takes longest. Use the lightest combination that satisfies the workflow.
For static SSH hosts, capability validation degrades to probe-based detection, because Crabbox does not install software on operator-owned machines:
--desktop: probe loopback VNC at127.0.0.1:5900over SSH (X11 checks for Xvfb/x11vnc; Wayland/GNOME checks for the compositor and WayVNC). Fail with a clear error if the desktop is not running.--browser: probe for a browser binary using the OS-specific search list; fail if none is found.--codeis rejected (managed Linux only).
This is intentional: if a static box does not expose the capability, the run
should fail loudly rather than silently fall back. macOS hosts can enable
Screen Sharing; Windows hosts need a VNC server bound to 127.0.0.1:5900.