Experimental — Hotcell is under active development and should not be used in production.

CLI

The hotcell CLI is the fastest way to run OCI images in microVMs. Pull an image, boot a VM, stream output. No server, no embedding — just run it.

Quick Start

terminal
$ hotcell run alpine -- echo "hello from a VM"
Pulling docker.io/library/alpine:latest...
hello from a VM

The CLI pulls the image (with layer caching), assembles a root filesystem, boots a microVM, streams console output to stdout, and exits with the guest's exit code. Logs and errors go to stderr, so piping works correctly.

Run Python

terminal
$ hotcell run -m 512 python:3.12-slim -- python3 -c "print('hello')"
Pulling docker.io/library/python:3.12-slim...
hello

Run with networking

terminal
$ hotcell run --network inet alpine -- wget -qO- http://example.com
Pulling docker.io/library/alpine:latest...
<!doctype html>
...

Usage

Environment variables

terminal
$ hotcell run -e NAME=hotcell alpine -- sh -c 'echo Hello $NAME'
Pulling docker.io/library/alpine:latest...
Hello hotcell

Volume mounts

Share host directories into the guest via virtio-fs. The format is HOST_PATH:GUEST_TAG, where the tag becomes the mount point inside the VM at /<tag>.

terminal
$ hotcell run -v /tmp/data:data alpine -- ls /data
Pulling docker.io/library/alpine:latest...
input.txt

Exit codes and piping

The CLI exits with the guest's exit code, and sends VM output to stdout while keeping logs on stderr. This makes it composable in shell pipelines and scripts.

exit codes
$ hotcell run alpine -- sh -c "exit 42"
$ echo $?
42
piping
$ hotcell run alpine -- cat /etc/os-release | grep PRETTY
PRETTY_NAME="Alpine Linux v3.21"

Pre-cache images

Use hotcell pull to download and cache image layers without running anything. Subsequent runs using the same image skip the download.

terminal
$ hotcell pull alpine:latest
Pulling docker.io/library/alpine:latest...
Cached: docker.io/library/alpine:latest

$ hotcell pull python:3.12-slim
Pulling docker.io/library/python:3.12-slim...
Cached: docker.io/library/python:3.12-slim

Options Reference

hotcell run

Flag
Default
Description
<IMAGE>
required
OCI image reference
-- <COMMAND>
required
Guest command (after --)
-e, --env
KEY=VALUE env var (repeatable)
-v, --volume
HOST:TAG volume mount (repeatable)
-m, --memory
256
VM memory in MiB
--cpus
1
Virtual CPUs
--timeout
30
Execution timeout (seconds)
--network
disabled
disabled, inet, or full
--workdir
Guest working directory
--backend
libkrun
libkrun or firecracker
--worker
auto
Worker binary path (env: HOTCELL_WORKER)
--firecracker-bin
firecracker
Firecracker binary path
--firecracker-kernel
vmlinux.bin
Kernel image path

hotcell pull

Flag
Default
Description
<IMAGE>
required
OCI image reference to pre-cache

Environment variables

Variable
Description
HOTCELL_WORKER
Path to hotcell-libkrun-worker binary
HOTCELL_BACKEND
Default VMM backend (libkrun or firecracker)
HOTCELL_FIRECRACKER_BIN
Path to Firecracker binary
HOTCELL_FIRECRACKER_KERNEL
Path to vmlinux kernel image
HOTCELL_LOG
Log filter (default: hotcell=warn). Uses tracing EnvFilter syntax.

Backend Selection

The CLI supports both VMM backends. Use --backend to select. The default is libkrun which works on macOS and Linux. Firecracker requires Linux with KVM.

firecracker backend
$ hotcell run --backend firecracker \
    --firecracker-bin /usr/bin/firecracker \
    --firecracker-kernel /var/lib/hotcell/vmlinux.bin \
    alpine -- echo "hello from Firecracker"
Pulling docker.io/library/alpine:latest...
hello from Firecracker

Worker binary

The libkrun backend requires the hotcell-libkrun-worker binary. The CLI discovers it automatically by checking: (1) the --worker flag or HOTCELL_WORKER env var, (2) the directory adjacent to the hotcell binary, (3) PATH.

Image References

The CLI normalizes short image references following Docker conventions. You don't need to type the full registry path — bare names are expanded to docker.io/library/<name>:latest.

normalization rules
alpine                    → docker.io/library/alpine:latest
alpine:3.19               → docker.io/library/alpine:3.19
myuser/myimage            → docker.io/myuser/myimage:latest
ghcr.io/owner/image:v1    → ghcr.io/owner/image:v1  (pass-through)