guides
Pause, suspend, and restore (lifecycle)
Free guest CPUs or host RAM without losing a persistent lab.
Pause vs suspend
| Command | Process | Host RAM | Status | Resume with |
|---|---|---|---|---|
grain pause | QEMU stays up | Still held | paused | grain resume |
grain suspend | QEMU stopped | Freed | suspended | grain restore |
grain stop | Stopped | Freed | ephemeral deleted / persistent stopped | grain start |
Pause freezes vCPUs via QMP (stop / cont). Good for a short break without tearing down networking.
Suspend applies to persistent VMs only. grain tries a qcow2 savevm snapshot when it can, then stops the process. Restore loads that snapshot if present; otherwise it cold-boots the disk.
grain new -p -n lab
# ... work ...
grain suspend lab
# hours later
grain restore labRules of thumb
- Ephemeral VMs: prefer
rmorstop(they are disposable) - Persistent labs:
suspend/restoreorstop/start startrejects asuspendedVM — userestore- Suspended VMs do not count toward running resource caps
Create path and latency
| Path | What happens | Typical ready time |
|---|---|---|
Cold grain new | New disk/seed + QEMU + guest boot + agent | ~seconds on grain-ubuntu (host work ~200 ms) |
Spawn grain new --from TEMPLATE | Clone disk + start (-loadvm if snapshotted) | Sub-second–few seconds when suspended |
Pool claim grain new --from-pool | Rename ready member + start (or rename-only if running) | Fastest assign path |
Daemon INFO logs help measure:
create timing— image / disk / seed / start / wait msspawn timing— from-template pathpool claim timing— claim + start (orrunning_mode=true)
Lean cold path (already default for goldens): agent-ready images use minimal cloud-init; growpart/resizefs is skipped unless the clone disk is larger than the base (grow deferred after agent). Agent wait polls at 50 ms.
The product <100 ms ready promise means assign a ready sandbox (pool/snapshot), not “full Ubuntu cold boot in 100 ms.”
Fast create: spawn and warm pool
# Template once
grain new -i grain-ubuntu -n golden -p --wait agent
grain suspend golden
# Spawn = clone + start (clone cost every time)
grain new --from golden -n w1
# Warm pool = pre-cloned members; claim renames + starts (or rename-only if running)
# config.yaml:
# warm_pool:
# template: golden
# size: 2
# running: false # true = keep members agent-ready (uses host RAM)
grain pool fill
grain new --from-pool -n w2
grain pool status
grain pool drain # delete ready members| Mode | Members | Claim |
|---|---|---|
Default (running: false) | Stopped/suspended disks (no host RAM) | Start with -loadvm when snapshotted |
running: true | Agent-ready, uses host RAM | Rename/untag only |
The daemon refills toward warm_pool.size after each claim; on grain up it also fills in the background when configured.
Desktop warm-path loop
- Boot and prepare a golden: create persistent sandbox, wait for agent, then More → Promote to golden + fill pool (suspends if running, sets
warm_pool.template/ size, restarts local daemon, fills). - Or set Settings → Warm pool (template, size, optional running mode) → Apply warm pool → Fill pool.
- New sandbox prefers From warm pool when ready > 0; empty/unconfigured states stay honest (cold boot message, no silent slow path).
- Multi-select Start runs a capacity preflight against host caps (
max_vms/ CPU / memory from the active daemon’sGET /info). - Activity drawer can filter by source (
desktop/cli/mcp/api).
Full Desktop surface: Grain Desktop.
API
POST /vms/{name}/pause·resume·suspend·restore·clonePOST /vmsbodyfrom— spawn from templatePOST /vmsbodyfrom_pool: true— claim from warm poolGET /pool·POST /pool/fill·POST /pool/claim·POST /pool/drainGET /activity— control-plane activity ringGET /info— version + resource caps (strings)