Build your own Daytona
Sandboxes for your agents, running as Firecracker microVMs on hardware you own. Create one, run commands in it, open a shell, expose it on a URL, then keep its workspace or let it sleep — from Rust with the hws crate, from its heyctl CLI, or from your agent over MCP. Each sandbox is just a deployment on Heyo Web Services, behind a load balancer you run.
A sandbox is a deployment with no route
On HWS, app-lb is the load balancer, autoscaler
and control plane. A managed deployment is a pool
of microVMs it boots and scales. Create one with
--no-route and it takes no HTTP
traffic at all — it is still autoscaled, and
reachable only through exec and
shell. That is the normal shape for
an agent sandbox.
Create
Register a deployment with no public
route, a size class, and a
/workspace data disk. Nothing
faces the internet until you say so.
Exec & shell
Run one command through
sh -c with stdout, stderr and
the exit code passed straight through, or
open an interactive PTY. Both start a VM if
none is running.
Expose
When the agent has something worth
showing, set route gives the
sandbox a hostname. --none
withdraws it from the proxy again.
Sleep or keep
With --idle-action retain, an
idle sandbox is stopped instead of
destroyed, and the next request or
exec resumes it with its
/workspace disk intact.
# Create a sandbox: no public route, a medium VM, an 8 GB /workspace disk heyctl create deployment sb-7f3a9c --no-route --port 8080 --size medium --disk-gb 8 # Stop it when idle instead of destroying it heyctl scale sb-7f3a9c --idle-action retain # Run a command in it (wakes the VM if it is asleep) heyctl exec sb-7f3a9c --cwd /workspace -- git status # Or drop into an interactive shell heyctl shell sb-7f3a9c # Expose it later, and withdraw it again heyctl set route sb-7f3a9c --host sb-7f3a9c.example.com heyctl set route sb-7f3a9c --none
An open shell counts as in-flight work, so the
pool will not scale to zero under it. Pass
--no-wake when you only want to talk
to a sandbox that is already running.
The same client the CLI uses
The hws
crate is a Rust client library for the app-lb
admin API, and the library behind the heyctl CLI.
cargo install hws gets you the CLI;
depend on it with
default-features = false and you get
the typed client without clap or a terminal
— and without pingora, openssl or the ACME
stack, since it shares only the wire format with
the server.
# Cargo.toml
[dependencies]
hws = { version = "0.1", default-features = false }
The service that hands out sandboxes holds the operator credential and gives each agent a token that reaches only its own sandbox:
use hws::{AdminScope, Client, ExecRequest, NewToken}; // The operator credential mints tokens… let admin = Client::builder("127.0.0.1:9090").basic("admin", "s3cret").build()?; let minted = admin.mint_token( &NewToken::new("agent-runner") .admin(AdminScope::Admin) .for_deployments(["sb-7f3a9c"]), ).await?; // …and the agent's client can only reach sb-7f3a9c. let lb = Client::builder("127.0.0.1:9090").token(minted.token).build()?; // Wakes the VM if it scaled to zero. A non-zero exit is Ok, not Err. let out = lb.exec("sb-7f3a9c", &ExecRequest::new("git status").cwd("/workspace")).await?; println!("{} (exit {})", out.stdout, out.exit_code);
- Async by default. The library is async, so it drops into the service that hands sandboxes to your agents.
-
Blocking when you want it.
The
blockingfeature addshws::blocking::Client, the same surface with theawaits taken out — which is what the CLI itself uses. -
Every CLI verb is an API call.
The client covers deployments, scaling,
exec, interactiveshell, secrets, auth providers and tokens, so anything you can script with heyctl you can drive from code. -
Scoped credentials. Mint an
app-token limited to one namespace or a set
of deployments — with
mint_tokenas above orheyctl token mint. A token scoped to deployments is refused the fleet-wide routes, minting included, so it can’t widen itself.
Let the agent drive its own sandbox
heyo-mcp is a Model Context Protocol server that gives coding agents such as Claude Code tools for HWS sandboxes and app-lb deployments. The agent creates a microVM, runs commands in it, and moves files in and out without a human writing glue.
-
sandbox_create— boot a microVM from an image, with a size class, working directory, env vars, open ports and setup hooks. -
sandbox_exec— runsh -cand get stdout, stderr and the exit code back. -
sandbox_read_file,sandbox_write_file— move files in and out; larger uploads go through a presigned URL. -
sandbox_stop,sandbox_start,sandbox_set_ttl— lifecycle. A stopped sandbox keeps its disk;sandbox_killdeletes both. -
applb_exec— run a command in a deployment’s guest, for sandboxes you created with heyctl.
Setup for Claude Code and the full tool list are in the MCP server docs.
One primitive, three shapes
Persistent workspaces
Give each agent a sandbox with a
/workspace disk and
--idle-action retain. It
sleeps when nobody is using it and resumes
on the next exec with the
checkout, dependencies and work in
/workspace still there.
Disposable headless runs
No UI, no route, no state to clean up.
Leave the idle action at
destroy and an idle VM is
killed along with its data disk, so the
next run starts from a fresh boot of the
image.
Previews on demand
Keep a sandbox private while the agent
works, then set route to put
what it built on a hostname — and
take it off again when the review is done.
Know what survives: the root filesystem is recopied
from the image on every boot, so the
/workspace data disk is the only
guest storage that outlives a stop. Keep state
there. Because exec and
shell go through app-lb, they work
wherever the admin API does — your agents
can be triggered from anywhere while the compute
stays on your machines.
Weighing your options? See how Heyo compares with other sandboxes →
Build your own cloud
Sandboxes for every agent, on hardware you own, driven from your own code.