VMs
github.com/solari-sdk/solari-sandbox-go, package solari. A VM is a session created with Create() and Kind: KindDesktop. It returns the same Sandbox handle a sandbox uses, plus StreamURL for the live view. Driving the GUI is not part of this surface. See the Go SDK hub for install and configuration.
go get github.com/solari-sdk/solari-sandbox-goCommands, Files, Code, and Git on it. Mouse, keyboard, screenshot, display, and clipboard have no Go binding. See What you cannot do.Contents
Client
The same Client that creates sandboxes. There is no separate CreateDesktop(): the flavour is a field on CreateOptions.
Methods
Create()
func (c *Client) Create(ctx context.Context, opts CreateOptions) (*Sandbox, error)With Kind: KindDesktop, provisions a GUI VM (POST /sandboxes) and returns a handle. Retry-safe, since it sends an idempotency key. The control channel is not opened yet.
Parameters:
ctxcontext.Context.optsCreateOptions: setKind: solari.KindDesktop. An emptyKinddefaults toKindSandbox.Template,CPU,MemMb,Envs,Metadata, andLifecycleall apply, plus the desktop-onlyResolution(e.g."1280x720") andRecord. See CreateOptions.
Returns: (*Sandbox, error), with Kind of KindDesktop and StreamURL set.
Errors: *PlanError (402 FeatureRequiresPlan) when the org lacks the desktop entitlement; also *AuthError, *ConcurrencyLimitError, *NoCapacityError, or *GatewayError.
Example:
import solari "github.com/solari-sdk/solari-sandbox-go"
client, _ := solari.NewClient(solari.ClientOptions{
APIKey: os.Getenv("SOLARI_API_KEY"),
BaseURL: "https://api.getsolari.com",
})
vm, err := client.Create(ctx, solari.CreateOptions{
Template: "office",
Kind: solari.KindDesktop,
CPU: 2,
MemMb: 4096,
})
if err != nil {
log.Fatal(err)
}
defer vm.Kill(ctx)
fmt.Println(vm.Kind) // "desktop"
fmt.Println(vm.StreamURL) // wss://.../stream/<id>
// Core namespaces work on a VM exactly as on a sandbox.
r, _ := vm.Commands.Run(ctx, "xdotool", solari.CommandOptions{
Args: []string{"getactivewindow"},
})
fmt.Println(r.Stdout)errors.As unwraps to the typed error, so a 402 is distinguishable from a capacity or auth failure:var pe *solari.PlanError; if errors.As(err, &pe) { /* needs the desktop plan */ }Connect()
func (c *Client) Connect(ctx context.Context, sandboxID string) (*Sandbox, error)Re-attaches to a running VM by id. Reads its view, then derives both the control URL and the stream URL from the gateway origin.
Parameters:
ctxcontext.Context.sandboxIDstring: the session id.
Returns: (*Sandbox, error). StreamURL is set when the session is a desktop, and empty otherwise.
Errors: *GatewayError if the id is unknown.
Example:
vm, err := client.Connect(ctx, "vm_abc123")
if err != nil {
log.Fatal(err)
}
if vm.StreamURL != "" {
fmt.Println("live view:", vm.StreamURL)
}SandboxView has no StreamURL field because the gateway’s toSandboxView never emits one. So Connect builds it as wsOrigin() + "/stream/" + id, the same way ControlURL has always been derived, and the result is identical to what Create decodes off the wire. This is intentional: adding a field the wire never populates would always unmarshal to the zero value. Do not "fix" it.Sandbox
A live session, GUI or headless. Construct via Create() or Connect().
Fields
Kind
Kind SandboxKindThe session flavour: KindDesktop ("desktop") or KindSandbox ("sandbox").
Example:
if vm.Kind == solari.KindDesktop { /* has a display */ }StreamURL
StreamURL stringThe wss:// RFB URL of the live view, carried from CreateSandboxResponse onto the handle. Hand it to a noVNC client to render or embed the screen.
Value: set for KindDesktop, empty for KindSandbox. A headless sandbox has no display, so an empty string is the correct answer, not a gap.
Example:
if vm.StreamURL == "" {
log.Fatal("not a desktop")
}Inherited members
Everything on the Sandbox page works unchanged on a VM: Connect(), Reconnect(), Connected(), Close(), Pause(), Resume(), Kill(), ID, ControlURL, ExpiresAt, and the Commands, Files, Code, and Git namespaces.
What you cannot do
There is no Go GUI surface and no Desktop type. These have no binding:
mouse.*,keyboard.*: pointer and key input.screenshot(): capture the screen as bytes.display.*,clipboard.*,open(): resolution, cursor, guest clipboard, launching apps.record.*: in-guest video capture.
Session-level Pause()/Resume() (snapshot the whole VM and bring it back) are ported — see Sandbox.Pause in inherited members above. Only in-guest screen recording has no Go binding.
To drive the GUI, use the TypeScript SDK (the complete reference surface) or the VM HTTP API. Mixing is supported: create and drive from TypeScript, then Connect() a Go handle to the same id for the compute work. One API key, one session, two clients.
