# BoxLite v0.10.0: Your agent needs more than a sandbox

> Source: <https://blog.boxlite.ai/boxlite-v0-10-0-your-agent-needs-more-than-a-sandbox>
> Published: 2026-10-14 23:44:59.092715+00:00

Tags: ai-agents, microvm, rust

**Cover description:** BoxLite 0.10.0 gives agents a filesystem that outlives the box, an address the world can reach, and a ceiling that holds under concurrency.

That is one sentence. Look at what it demands.

The agent has to install a toolchain and keep it. It has to write files and still have them an hour later. It has to run a dev server that someone who is not the agent can open in a browser. And it has to do all of that inside limits, because "an agent that provisions compute" and "an agent that provisions compute you pay for" are the same sentence.

In 0.9.7 you could not do that through the API. In 0.10.0 you can. That is the release.

246 commits since 0.9.7, and the three largest areas of change are the API, the infrastructure, and the console  not the VM. The runtime was never the bottleneck. Everything an agent needs *around* the runtime was.

```
POST /v1/boxes
{
  "image": "python:3.11-slim",
  "volumes": [{ "managed_volume": "agent-home", "guest_path": "/workspace" }],
  "network": {
    "outbound": { "mode": "enabled", "allow_net": ["api.openai.com"] },
    "inbound":  { "mode": "enabled" }
  }
}
```

Three lines that were not possible over REST before this release: a managed volume attached by name, an egress allowlist that actually holds, and an inbound switch that makes the box's services publicly reachable.

Managed volumes existed in 0.9.x if you were the internal box-creation path. Over REST they were unreachable, which meant every agent building on the public API rebuilt its world on every run.

Now:

`POST`, `GET`, `GET /:id`, `DELETE` on `/v1/volumes`  full lifecycle over REST

Volumes attach in the same call that creates the box

Addressed by **id or name**. `managed_volume: "agent-home"` and `managed_volume: "vol_01K2EXAMPLE"` both resolve

Single-file mounts, for when a directory is the wrong unit

S3-backed volumes through the same interface

A volumes console, and a rebuilt create-box dialog

The `volume://` scheme is gone. It used to live inside a polymorphic `source` string, which is a parser nobody meant to write, and the CLI, the SDKs and the wire had all drifted on how to read it. `VolumeSpec` now carries `managed_volume` and `host_path` as separate typed fields. Two typed fields cannot disagree.

This is the half of stop-and-wake that makes it safe to use. A box that stops mid-run loses its disk. A volume does not, and the next box mounts it.

"Preview on a public URL" is a networking problem, and it landed here:

Public box service traffic routes through the API, proxy, runner, and guest-port tunnel path

Box network tunnels are proxied through the API

Local TCP port publication with automatic or fixed host ports, surfaced through the box-info APIs across REST, CLI and SDKs

Tunnel listener forwarding local TCP and Unix listeners on prepared tunnels, a fresh tunnel per accepted client, wire protocol unchanged

Two constraints shipped with it, both on purpose. OCI `EXPOSE` is metadata, never an instruction that opens a host listener. Remote runtimes stay tunnel-first. Each published listener is bounded at 256 concurrent proxied connections.

And a fix that matters more than its size: a tunnel `CONNECT` against a stopped box used to drop the stream silently. It now rejects. Silent failure is the most expensive kind in an agent loop, because the agent will retry it forever.

Every platform ships quota. Most ship it checked on `create`, which is where it does the least good.

0.10.0 enforces per-organization ceilings  cpu, memory, disk, gpu, plus maximum concurrent boxes  on **every path that adds or grows usage**: create, start, warm-pool assignment, proxy auto-resume, and resize. Warm-pool assignment and auto-resume both add usage without anyone calling create. That is precisely how a "we have quotas" platform ends up with a runaway bill.

Underneath: a Redis pending-reservation using atomic Lua with TTL self-heal, checked against summed box-table usage. A projected total over a ceiling is rejected with a 400 before anything is allocated.

Metering grew up with it. Finalized box usage exports to the commerce service through an outbox, open allocations are snapshotted, and the console now binds Usage to the quota API, quotes box price from published usage rates, and confirms plan changes on a page that shows exactly what is queued.

If you are the person who signs off on an agent platform, this section is the one that matters.

Three holes in `allow_net` enforcement are closed. Each was a case where the policy applied in one direction but not another:

UDP egress was not covered

The host alias IP was not covered

Host checks were bound to the requested destination, not the **resolved** one

The third is the one to sit with. A hostname that passes the check and then resolves somewhere else was never checked at all.

All three are breaking changes, because traffic that used to escape no longer does. That is the correct direction, and it is worth reading carefully if you were relying on the gap without knowing it. We would rather tell you than let you find out.

Alongside: structured container capability controls, no capability mutation from privileged mode, host sandbox grants separated from guest networking, and a minimal guest rootfs to boot from.

A small thing that says a lot about where the API is going. Send host port publication to the REST API and you no longer get `property ports should not exist`. You get:

host port publication is local-only; use the box network tunnel endpoint to reach a guest service

Four implementations of `CreateBoxRequest` had disagreed about which options a remote caller may set. One let a client switch the sandbox off. One refused nothing. Five fields were validated, audit-logged, and then silently dropped at the mapper. They are now either wired through or refused with a sentence that names the alternative.

0.10.0 earns the middle number. Before you bump:

`auto_pause` is now `auto_stop`, across the whole stack. The field never described a pause  the core has no pause operation, and the policy performs a real stop with no memory retention. The old name also collided with `BoxStatus::Paused`, which is the genuine SIGSTOP freeze taken during clone and export.

`volume://` is removed from the wire. Use `managed_volume` or `host_path`.

The REST API rejects host-only box options instead of dropping them silently.

`allow_net` now applies to UDP egress, the host alias IP, and resolved destinations.

The ssh-gateway is removed.

Box images move to the v0.1.0 line, relocated under `apps/`.

Tunnel half-close is owned by the core, which tolerates a hung-up peer.

The open-source runtime and the managed Cloud share the same SDK call runs against a box on your laptop or a box on our fleet a URL and an API key is the whole difference.

New accounts start with $100 for BoxLite Cloud in credits: [https://app.boxlite.ai](https://app.boxlite.ai)

Repo: [https://github.com/boxlite-ai/boxlite](https://github.com/boxlite-ai/boxlite)

Docs: [https://docs.boxlite.ai](https://docs.boxlite.ai)
