reference

HTTP API reference (REST daemon)

Daemon REST API over unix socket or TCP for automation and the Go/TypeScript SDKs.

Connect

Unix socket (default CLI path)

bash
curl --unix-socket ~/.grain/grain.sock http://grain/healthz
curl --unix-socket ~/.grain/grain.sock http://grain/vms

TCP (when api: 127.0.0.1:7474 is set — default)

bash
curl -s http://127.0.0.1:7474/healthz
curl -s http://127.0.0.1:7474/openapi.yaml

Auth: if api_token is configured, send Authorization: Bearer <token>. GET /healthz stays open.

Machine-readable schema

Client identification

Mutating clients should send User-Agent and/or X-Grain-Client with one of: cli, desktop, mcp, sdk. The daemon records this on activity events so Desktop can filter by source.

Common routes

MethodPathNotes
GET/healthzLiveness
GET/infoVersion + resource caps (see below)
GET/metricsPrometheus text
GET/activityRecent control-plane activity ring
GET/openapi.yamlSpec
GET/POST/vmsList / create
GET/DELETE/vms/{name}Get / delete
POST/vms/{name}/startStart persistent
POST/vms/{name}/shutdownStop
POST/vms/{name}/cloneOffline clone (stopped/suspended source)
POST/vms/{name}/pauseQMP stop
POST/vms/{name}/resumeQMP cont
POST/vms/{name}/suspendFree RAM
POST/vms/{name}/restoreFrom suspended
POST/vms/{name}/execAgent exec (buffered=true|false)
GET/vms/{name}/agent/healthAgent health
POST/vms/{name}/agent/deployDeploy/refresh agent over SSH (binary on daemon host)
GET/vms/{name}/statsGuest stats
GET/vms/{name}/metricsHost-side guest stats history (metrics.ring) when enabled
PUT/GET/vms/{name}/cpFile/tar copy
GET/POST/DELETE/vms/{name}/fs/*readdir, stat, mkdir, remove
POST/DELETE/vms/{name}/forwardsLive TCP forwards
GET/poolWarm pool inventory
POST/pool/fillFill pool to configured size
POST/pool/claimClaim one member ({"name":"…"} optional)
POST/pool/drainDelete ready pool members
GET/POST/DELETE/secretsHost secrets
POST/vms/{name}/secrets/{secret}Inject secret

GET /info

JSON object of strings (stable for simple clients):

KeyMeaning
name"grain"
versionDaemon version
max_vmsCap on concurrent running/creating VMs (0 = unlimited)
max_cpus_totalSum of vCPUs across running/creating
max_memory_mb_totalSum of MemoryMB across running/creating
max_cpus_per_vmPer-VM CPU cap
max_memory_mb_per_vmPer-VM memory cap

Desktop bulk-start preflight reads these from the active host (local or remote).

Activity

GET /activity?since=<id>&limit=N returns recent control-plane mutations (create/start/stop/rm/exec/pool/…). Events include source (cli / desktop / mcp / sdk / api), action, target, status, timings. Ring is persisted under data_dir/activity.json across daemon restarts.

Warm pool

MethodPathBody / notes
GET/pool{enabled, template, desired, ready, members, running}
POST/pool/fillClone until ready == desired
POST/pool/claimOptional {"name":"work-1"}
POST/pool/drainDeletes ready members

Config: warm_pool.template / size / runningconfig reference.

Create query parameters

QueryValues
stream=1NDJSON create progress
wait=auto (empty), ssh, agent, userdata, bootstrap
timeout=Go duration, e.g. 3m

Create body (highlights)

FieldNotes
name, image, cpus, memory_mb, disk_gb, persistentStandard create
fromSpawn from stopped/suspended template (fast -loadvm when snapshotted)
from_poolClaim warm-pool member (true; mutually exclusive with from)
metrics_enabledHost-side guest stats ring (default follows daemon config; usually on)
wait / timeoutAlso via query string
bash
# Cold create with progress
curl -N --unix-socket ~/.grain/grain.sock \
  -H 'Accept: application/x-ndjson' \
  -H 'Content-Type: application/json' \
  -H 'X-Grain-Client: cli' \
  -d '{"persistent":false}' \
  'http://grain/vms?stream=1&wait=agent&timeout=3m'

# Fast spawn from suspended template
curl --unix-socket ~/.grain/grain.sock -H 'Content-Type: application/json' \
  -d '{"from":"golden","name":"work1"}' http://grain/vms

# Claim from warm pool
curl --unix-socket ~/.grain/grain.sock -H 'Content-Type: application/json' \
  -d '{"from_pool":true,"name":"work2"}' http://grain/vms

SDKs

Prefer typed clients when embedding: