Quick start
Install grain, drop in a starter config, and open a shell in a Linux microVM.
From zero to a working sandbox in a few minutes. When you finish this page you will have:
- The grain CLI and QEMU installed
- An optional starter config at
~/.grain/config.yaml - A running microVM you can shell into and tear down
Platforms: macOS and Linux (amd64 / arm64). Not supported: Windows or WSL.
Deep dives live elsewhere: Install · First sandbox tutorial + demo · Config reference.
1. Install
macOS
curl -fsSL https://raw.githubusercontent.com/cxdy/grain/main/scripts/install.sh | bash
brew install qemu
grain doctor
Linux (Debian / Ubuntu)
curl -fsSL https://raw.githubusercontent.com/cxdy/grain/main/scripts/install.sh | bash
sudo apt-get update
sudo apt-get install -y qemu-system qemu-utils
grain doctor
Linux (Fedora)
curl -fsSL https://raw.githubusercontent.com/cxdy/grain/main/scripts/install.sh | bash
sudo dnf install -y qemu-system-x86 qemu-img
grain doctor
grain doctor checks QEMU, data dirs, and soft-warns if the guest agent binary is missing (OK for first pull of the golden image).
Other install paths (release binary, go install, from source): Install grain.
2. Starter config (optional)
Defaults work with no config file. A starter file is still useful for size defaults and a named profile.
mkdir -p ~/.grain
cat > ~/.grain/config.yaml <<'EOF'
# ~/.grain/config.yaml — starter for local use
data_dir: ~/.grain
socket: ~/.grain/grain.sock
api: 127.0.0.1:7474
# Defaults for `grain new`
image: grain-ubuntu # after: grain image pull grain-ubuntu
cpus: 2
memory_mb: 2048
disk_gb: 8
ssh_user: ubuntu
ready_timeout: 2m
log_level: info
# Soft caps (stop runaway sandboxes)
max_vms: 8
max_cpus_total: 16
max_memory_mb_total: 32768
# Named profile: grain new --profile work
profiles:
work:
cpus: 4
memory_mb: 4096
disk_gb: 20
image: grain-ubuntu
mounts:
- {host: ".", guest: "/work"}
forwards:
- {guest_port: 3000} # host port auto-assigned
EOF
| Setting | Meaning |
|---|---|
api |
Daemon TCP listen (CLI also uses the unix socket by default) |
image |
Default base image id for creates |
cpus / memory_mb / disk_gb |
Size defaults for grain new |
profiles.work |
Reusable create knobs + mount + port forward |
All fields: Configuration reference. Remote / team hosts need a token and different bind rules — see Remote sandbox host.
3. First sandbox
# Start the local daemon (once per session)
grain up
# Download the golden base image once (agent baked in)
grain image pull grain-ubuntu
# Create a microVM (uses defaults / profile)
grain new
# or: grain new --profile work
# Shell in (name optional if only one VM)
grain sh
# One-shot command without an interactive shell
grain x -- uname -a
# List and clean up
grain ls
grain rm
grain down
You should see create progress (image → disk → seed → boot → agent), then something like:
created sbox-1 status=running image=grain-ubuntu persist=false ssh=:PORT
next: grain sh sbox-1
| Command | What it does |
|---|---|
grain up / down |
Start / stop the local daemon |
grain image pull |
Download a base image once |
grain image ls |
Show local / catalog images |
grain new |
Create a microVM |
grain sh |
Interactive shell (agent PTY when healthy) |
grain x -- … |
One-shot exec in the guest |
grain ls / rm |
List / delete VMs |
Ephemeral is the default: rm, stop, or daemon restart removes the VM. Use grain new -p for a persistent disk (stop / start later).
4. Real workloads (act & k3s)
These are the two features most people try after a plain shell.
GitHub Actions — grain act
From a repo with .github/workflows/:
grain act -- -l # list workflows / jobs
grain act -- -j test # run a job in an ephemeral microVM
Docker + act run inside the guest so host Docker stays clean. Full guide: GitHub Actions with act.
Throwaway k3s lab
grain new --preset k3s -n lab -p --wait userdata
grain fwd ls lab # host port → guest 6443
Pull kubeconfig and use host kubectl — see k3s recipe.
5. Useful next commands
Once grain up is running and an image is local:
# Mount the current directory into the guest
grain new -v "$(pwd):/work"
grain sh
# guest: ls /work
# Publish a host port to a guest port
grain new -P 8080:80
grain fwd ls
# Named profile from the starter config
grain new --profile work
# Keep the disk across stop/start
grain new -p -n lab
grain stop lab
grain start lab
# Guest file copy (agent preferred)
grain cp ./hello.sh lab:/tmp/hello.sh
grain x lab -- cat /tmp/hello.sh
# Docker-in-guest preset
grain new --preset docker
More: Profiles & presets · Mounts · Networking.
6. If something fails
grain doctor
grain logs <name> # guest serial
grain logs --qemu <name> # hypervisor log
Common fixes:
| Symptom | Try |
|---|---|
grain: command not found |
Ensure install dir is on PATH (/usr/local/bin or ~/.local/bin) |
| Doctor fails on QEMU | Install QEMU (step 1); reopen the terminal |
| Image pull fails | Check network; list images with grain image ls |
| Create hangs / no shell | Prefer grain-ubuntu; see Troubleshooting |
7. Automation (optional)
The daemon exposes HTTP on the unix socket and optional TCP (api: 127.0.0.1:7474). Spec: OpenAPI.
# curl over the local socket
curl --unix-socket ~/.grain/grain.sock http://grain/vms
| SDK | Install |
|---|---|
| Go | go get github.com/cxdy/grain/client |
| TypeScript | npm install @cxdy/grain |
| Python | pip install grainvm |
Next steps
- GitHub Actions (act) · k3s lab
- Your first sandbox — interactive demo + deeper walkthrough
- Core concepts — daemon, images, agent, ephemeral vs persistent
- Guides — images, agent, mounts, proxy, remote host
- CLI reference · HTTP API