Your metal. Machines on demand.

Linux VMs that manage themselves. Create in seconds, snapshot everything, resume in milliseconds. On your hardware, open source.

curl -fsSL bhatti.sh/install | sudo bash
GitHub →
bhatti
CORE

Real machines. Zero waste.

01

Real VMs. Not containers.

Every machine runs its own Linux kernel. Separate filesystem, separate network, separate process space. Not a namespace trick — a separate computer.

02

Snapshot everything. Not just files.

When bhatti snapshots a machine, it captures everything: running processes, open file descriptors, TCP connections, in-memory state. Resume picks up exactly where it left off.

03

Idle machines cost nothing.

Idle machines pause their CPUs automatically. Left idle longer, they snapshot to disk and free all memory. Any request wakes them transparently — you never manage this.

SYS.PERFORMANCE // LATENCY
Operation p50 p99
Create a machine 266ms 291ms
Snapshot to disk (1024MB) 485ms 807ms
Wake on request (cold) 360ms 430ms
Wake on request (warm) 3.7ms 10.2ms
Destroy a machine 87ms 96ms
Run a command 12ms 14ms
20 commands in parallel 32ms 39ms

Hetzner AX102, btrfs, bhatti v1.11.0, CLI on the daemon host.
Reproduce: bench/run.sh.

SYS.ARCHITECTURE

How it works

Click any component to explore.

Host Machine
bhatti daemon :8080
REST / WS API
routes, proxy, NDJSON streaming
Thermal Manager
hot → warm → cold lifecycle
Firecracker Engine
create, exec, snapshot, restore
SQLite + age
state, secrets, users
Binary wire protocol · TCP :1024
daemon ⇌ lohar
Firecracker microVM ×N
kernel 6.1 · ubuntu 24.04
hot warm cold
lohar PID 1
exec / shell
PTY sessions
file ops
port forward
eth0 (kernel ip=)
Host Storage virtio-blk
rootfs.ext4
config.ext4
vol-*.ext4
/var/lib/bhatti/sandboxes/
↕ virtio-net
brbhatti-N bridge
TAP device
iptables NAT

CAPABILITIES

What people use it for

One sandbox per AI agent

The original use case for bhatti. Each agent gets its own Linux VM. Snapshot at any tool call so you can branch from that exact moment if the run goes sideways.

# Each agent gets its own Linux VM
$ bhatti create --name agent --image ai
sandbox/agent created (2 vCPU, 2048 MB)

# Snapshot before a risky tool call
$ bhatti snapshot create agent --name pre
 checkpoint "pre" created (2048MB)

# Run goes sideways? Branch from there:
$ bhatti snapshot resume pre --name retry
 restored, state intact

# 40 agents on a Pi; idle ones go cold
$ bhatti list | grep agent | wc -l
40

Preview environments per PR, free when idle

One sandbox per pull request. `bhatti publish` gives it a public URL with TLS. Idle previews pause themselves, snapshot to disk after thirty minutes, and wake on the next request in ~50 ms. No rented infrastructure.

# CI spins up a preview from your image
$ bhatti create --name pr-247 --image base
$ bhatti exec pr-247 -- ./deploy.sh
$ bhatti publish pr-247 -p 3000
Published: https://pr-247.bhatti.sh

# Days later — the sandbox is cold
$ bhatti list
NAME    STATUS    THERMAL  URL
pr-247  stopped   cold     https://...

# Reviewer opens the URL — auto-wake
$ curl -s https://pr-247.bhatti.sh
{"build":"ok"}    # wake + serve, ~50ms

Anything you can rootfs is yours

OCI pull, Docker import, or save a running sandbox. Whatever you put in a rootfs becomes a Linux VM that snapshots, resumes, and idles for free. Postgres, browser automation, full desktops — it all just works.

# Pull an OCI image as a rootfs
$ bhatti image pull ghcr.io/myorg/devbox
 pulled, converted (820MB)

# Or import a local Docker image
$ bhatti image import my-app:latest
 imported

# Or save a running sandbox as a base
$ bhatti image save dev --name stack
 saved "stack" (1024MB)

# Whichever path — snapshottable real VM
$ bhatti create --name web --image stack
$ bhatti snapshot create web --name ready
 checkpoint "ready" created (1024MB)
CLI

Every command

Single binary. bhatti serve starts the daemon, everything else talks to its API.

bhatti create <name> [--cpus N] [--memory MB] [--image NAME] [--init CMD] [--env K=V] [--volume V:/mnt] [--secret K] [--file local:guest] [--keep-hot] [--hugepages]
Create a new machine
bhatti destroy <name> [-y]
Destroy a machine (alias: rm)
bhatti edit <name> [--keep-hot] [--allow-cold]
Update machine settings
bhatti list [-o wide]
List your machines (alias: ls)
bhatti inspect <name>
Show machine details (alias: info)
bhatti start <name> [--force]
Resume a stopped machine
bhatti stop <name>
Snapshot and stop a machine
Execution & shells
bhatti exec <name> -- <cmd> [--timeout S] [--detach]
Run a command
bhatti shell <name> [--new]
Interactive terminal (Ctrl+\ to detach)
bhatti ps <name>
List active sessions in a machine
bhatti ports <name>
List listening TCP ports inside a machine
Files & Secrets
bhatti file read <name> <path>
Read a file
bhatti file write <name> <path> < stdin
Write a file (atomic)
bhatti file ls <name> <path>
List a directory
bhatti secret set <key> <value>
Store an encrypted secret
bhatti secret list
List secret names
bhatti secret delete <key>
Delete a secret
Images
bhatti image list
List available images
bhatti image pull <ref> [--name N] [--auth U:T]
Pull an OCI image from a public registry
bhatti image import <docker-ref> | --tar <path> [--name N]
Import from local Docker or a tarball
bhatti image save <sandbox> --name <image>
Save a running machine's rootfs as a reusable image
bhatti image delete <name> [-y]
Delete an image
bhatti image share <image> --user <name>...
Share an image with specific users (server-only)
bhatti image unshare <image> --user <name>...
Revoke image access (server-only)
Snapshots
bhatti snapshot create <sandbox> --name <snap>
Checkpoint a running machine (memory + processes + disk)
bhatti snapshot list
List snapshots
bhatti snapshot resume <snap> [--name <new>]
Resume a snapshot into a new machine
bhatti snapshot delete <snap> [-y]
Delete a snapshot
Networking & Publishing
bhatti publish <name> -p <port> [-a <alias>] [--shell]
Publish a port → https://alias.bhatti.sh
bhatti unpublish <name> -p <port>
Remove a published port
bhatti share <name> [--revoke]
Generate a web shell URL
Volumes
bhatti volume create --name <v> --size <MB>
Create a persistent volume
bhatti volume list
List volumes
bhatti volume delete <name> [-y]
Delete a volume
bhatti volume resize <name> --size <MB>
Resize a volume (grow only)
bhatti volume clone <src> --name <new>
Clone a volume (point-in-time copy)
bhatti volume backup <name>
Back up a volume to S3-compatible storage
bhatti volume backup-list <name>
List backups for a volume
bhatti volume restore <name> --backup-id <id>
Restore a volume from a backup
bhatti volume backup-delete <name> <id> [-y]
Delete a volume backup
Server & admin
bhatti serve
Start the daemon (server-only)
bhatti setup
Configure CLI endpoint + API key
bhatti version
Print version, check for updates
bhatti update [--cli-only] [--tiers <list>]
Update bhatti
bhatti completion <bash|zsh|fish>
Generate a shell completion script
bhatti user create --name <u> [--max-sandboxes N] [--max-cpus N] [--max-memory MB]
Create a user (server-only)
bhatti user list
List users (server-only)
bhatti user rotate-key <name>
Rotate a user's API key (server-only)
bhatti user delete <name> [-y]
Delete a user (server-only)
bhatti admin status
One-shot system overview (server-only)
bhatti admin events [--type T] [--since 24h] [--user U] [--sandbox S]
Query the event log (server-only)
bhatti admin metrics [--since 1h]
Query metrics snapshots (server-only)
DEPLOY.SELF_HOST

Run it on your hardware.

One command. Any Linux machine with KVM. Downloads pre-built binaries, a kernel, and an Ubuntu 24.04 rootfs. No Docker, no containers, no orchestration layer.

Requirements

  • Linux (x86_64 or ARM64)
  • Hardware virtualization (/dev/kvm)
  • Root access for daemon (Firecracker requirement)

Running on: two Raspberry Pi 5s with NVMe HATs at home, a Hetzner AX102 in production.

# Install on any Linux box with KVM
$ curl -fsSL bhatti.sh/install | sudo bash
==> Installing bhatti (server, minimal tier)
     Firecracker + jailer
     bhatti, lohar, kernel, rootfs
     admin API key in ~/.bhatti/config.yaml
     bhatti.service started

# Create a sandbox — no setup step needed
$ bhatti create --name dev
sandbox/dev created (1 vCPU, 1024 MB)

$ bhatti exec dev -- uname -a
Linux dev 6.1.155 #1 SMP aarch64 GNU/Linux

# Add a teammate; let them drive it remotely
$ sudo bhatti user create --name alice
bht_alice_abc123...

# Then on their machine:
$ bhatti setup --url https://api:8080 \
               --token bht_alice_abc123
 authenticated (0 sandboxes)