# Sandboxes for AI Agents | Volcano

URL: https://volcano.dev/features/sandboxes

> Run LLM-generated code in an isolated VM. Keep files across commands, suspend for free, and use Python, Node.js, or custom dependencies.

## Give your agent a computer to run code on

Give your agent an isolated VM to run code, edit files, and preview apps, with a workspace that stays intact between commands.

```console
$ volcano cloud sandboxes exec --preset python3.12 -- python -c 'print(6 * 7)'
42
# one command, one temporary VM, terminated when it finished
$ volcano cloud sandboxes run --preset node22
{ "id": "7cdbb4e3-…", "state": "starting", "memory_mb": 1024 }
$ volcano cloud sandboxes exec 7cdbb4e3-… -- node -e 'console.log(process.version)'
v22.22.0
$ volcano cloud sandboxes suspend 7cdbb4e3-…
# processes and files kept, and suspended time is not charged
```

## Give generated code its own place to run

An agent needs to test the code it writes, analyze a file, or start an app. Volcano Sandboxes give each hosted session its own isolated VM, with commands, files, and HTTP access.

Run a single snippet in a temporary sandbox that cleans up when it finishes. For work that takes several steps, keep a session and reuse its files and background processes. Suspend it between tasks and resume where it left off.

## One workspace from the first command to the last

*Work across steps*

An agent can write a script, run it, and use the results in its next step. A session keeps files in /workspace and background processes alive between commands. A nonzero exit comes back as output for the agent to read, not as an error.

- Use one-shot execution for a single snippet
- Reuse files across commands in a session
- Retry with the same request ID without rerunning code

```console
sandbox> python /workspace/analyze.py /workspace/sales.csv
revenue by region   NA 4.2M · EMEA 3.1M · APAC 2.4M
saved /workspace/monthly.csv, /workspace/revenue.png
sandbox> python /workspace/growth.py --quarter 3
fastest growth in Q3: APAC, up 18%
✓ the second script read what the first one saved
```

## Stop paying while the agent waits

*Pause between tasks*

Suspend a session while the agent waits for a reply or approval. Resume with its files and processes intact. Suspended time is free, and snapshots are included.

- Keep files and processes through a pause
- Resume within the session’s lifetime
- Terminate when done to remove the workspace

```console
$ volcano cloud sandboxes suspend 7cdbb4e3-…
state  suspending → suspended
# no runtime charged while it waits
$ volcano cloud sandboxes resume 7cdbb4e3-…
state  resuming → running
$ volcano cloud sandboxes exec 7cdbb4e3-… -- ls /workspace
http.log  monthly.csv  revenue.png  sales.csv
✓ files kept, and the server on port 8080 still answers
```

## Open the app running in the sandbox

*Preview what it builds*

Start a server in the session, then request a credential for its port. Share the preview with a signed-in user by granting access to that session.

- Credentials cover one session and one port
- Credentials expire within five minutes
- HTTP, WebSocket, SSE, and gRPC share one URL

```console
$ volcano cloud sandboxes exec 7cdbb4e3-… -- sh -c 'python -m http.server 8080 >/workspace/http.log 2>&1 &'
# then, from your backend
session.access(8080)              url, token · expires in 5m
GET  X-Volcano-Sandbox-Token: …    200 OK
WS   same URL, same token          101 Switching Protocols
✓ this session and this port only, for five minutes at most
```

## What your agent can use

- **An isolated VM per session**: Hosted sessions get a private workspace with 1 GiB of memory on Hobby or up to 2 GiB on Superagent.
- **Python, Node.js, or custom dependencies**: Start with python3.12 or node22, or deploy a Dockerfile fragment with the packages your agent needs.
- **A workspace that resumes**: Suspend between tasks and resume with files and processes intact.
- **App previews over HTTP**: Reach a running server with credentials scoped to its session and port, valid for at most five minutes.
- **Runtime included in each plan**: Hobby includes 5 GB-hours a month and Superagent includes 20. Usage is configured memory multiplied by running time.
- **MCP, CLI, API, and SDKs**: Give your agent MCP tools to run code, work with files, and manage sessions. Or use the CLI, REST API, or JavaScript, Python, and Ruby SDKs.

## Run code in your first sandbox

### Agent session

```javascript
import { VolcanoClient } from '@volcano.dev/sdk';

// Sessions are managed with a service key, so this runs in a function or on
// your own server, never in the browser.
const client = new VolcanoClient({
  apiUrl: process.env.VOLCANO_API_URL ?? 'https://api.volcano.dev',
  anonKey: process.env.VOLCANO_ANON_KEY,
  accessToken: process.env.VOLCANO_SERVICE_KEY,
});
const projectId = process.env.VOLCANO_PROJECT_ID;

const created = await client.sandboxes.create(projectId, {
  preset: 'python3.12',
  region: 'us-east-1',
  maxDurationSeconds: 1800,
});
if (created.error) throw created.error;
const session = created.data;

try {
  // Creation returns while the VM is still starting. Poll, with a deadline.
  const deadline = Date.now() + 120_000;
  while (session.state !== 'running') {
    if (Date.now() >= deadline || ['unknown', 'terminated'].includes(session.state)) {
      throw new Error(`Session unavailable: ${session.state}`);
    }
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const refreshed = await session.refresh();
    if (refreshed.error) throw refreshed.error;
  }

  // Files stay in /workspace for every later command in this session.
  const written = await session.files.write(
    '/workspace/analyze.py',
    new TextEncoder().encode(agentScript),
  );
  if (written.error) throw written.error;

  // Keep the request ID with the command. Retrying with it returns the stored
  // result, and a command whose outcome is unknown is never run again.
  const requestId = crypto.randomUUID();
  const run = await session.exec('python /workspace/analyze.py', { requestId });
  if (run.error) throw run.error;

  // A nonzero exit is data for the agent to read, not a platform error.
  console.log(run.data.exitCode, run.data.stdout, run.data.stderr);

  // Serve what it built, and reach it with a credential for this session and
  // port.
  const served = await session.exec('python -m http.server 8080 >/workspace/http.log 2>&1 &');
  if (served.error) throw served.error;
  const access = await session.access(8080);
  if (access.error) throw access.error;

  // The command returns before the server listens, and a request sent too early
  // gets a 502. Poll a read-only GET, with a deadline, before real traffic.
  const headers = { 'X-Volcano-Sandbox-Token': access.data.token };
  const ready = Date.now() + 30_000;
  let response = null;
  while (!response || response.status === 502) {
    if (Date.now() >= ready) throw new Error('Preview server did not start listening');
    await new Promise((resolve) => setTimeout(resolve, 500));
    response = await fetch(access.data.url, { headers }).catch(() => null);
  }
  console.log(response.status);
} finally {
  const stopped = await session.terminate();
  if (stopped.error) throw stopped.error;
}
```

### Python

```python
import os
import time
from uuid import uuid4

from volcano_sdk import VolcanoClient

client = VolcanoClient(
    anon_key=os.environ["VOLCANO_ANON_KEY"],
    service_key=os.environ["VOLCANO_SERVICE_KEY"],
    api_url=os.environ.get("VOLCANO_API_URL", "https://api.volcano.dev"),
)
project_id = os.environ["VOLCANO_PROJECT_ID"]

# One command in a temporary sandbox, terminated before the result returns.
# Retrying with the same request_id never runs the code a second time.
request_id = str(uuid4())
result = client.sandboxes.exec(
    project_id,
    'python -c "print(42)"',
    region="us-east-1",
    preset="python3.12",
    request_id=request_id,
)
print(result.stdout, result.exit_code)

# A session for work that spans several commands. Leaving the block requests
# termination, even when the body raises.
with client.sandboxes.create(
    project_id,
    region="us-east-1",
    preset="python3.12",
    max_duration_seconds=300,
) as session:
    for _ in range(60):
        if session.refresh().state == "running":
            break
        time.sleep(1)
    else:
        raise TimeoutError("Sandbox did not become ready")

    session.files.write("/workspace/input.bin", bytes(range(256)))
    assert session.files.read("/workspace/input.bin") == bytes(range(256))
    print(session.exec("wc -c /workspace/input.bin").stdout)
```

### CLI

```bash
# One command in a temporary sandbox. Prints the output and exits with the
# command's exit code.
volcano cloud sandboxes exec --preset python3.12 -- python -c 'print(42)'

# A session that outlives the command. Check get until it is running.
volcano cloud sandboxes run --preset python3.12 --duration 1800
volcano cloud sandboxes get SESSION_ID
volcano cloud sandboxes files write SESSION_ID /workspace/input.bin < input.bin
volcano cloud sandboxes exec SESSION_ID -- sh -c 'python -m http.server 8080 >/workspace/http.log 2>&1 &'

# A prompt that runs one command per line. exit detaches and leaves it running.
volcano cloud sandboxes shell SESSION_ID

# Keep it for later with its files and processes, then bring it back
volcano cloud sandboxes suspend SESSION_ID
volcano cloud sandboxes resume SESSION_ID
volcano cloud sandboxes terminate SESSION_ID

# Save a preset and memory size as a template (2048 MB needs Superagent)
volcano cloud sandboxes templates create analysis --preset python3.12 --memory 2048
volcano cloud sandboxes run --template TEMPLATE_ID

# The same commands against Docker-backed sandboxes on your machine
volcano start
volcano sandboxes exec --preset node22 -- node -e 'console.log(42)'
```

### Custom template

```bash
# ./sandbox/Dockerfile is a fragment. Volcano supplies the base image and the
# supervisor, so it has no FROM, ENTRYPOINT or USER:
#
#   RUN dnf install -y python3.12 && dnf clean all
#   COPY app.py /workspace/app.py
#   CMD ["python3.12", "/workspace/app.py"]

# Upload the directory. The template ID and request ID print before the
# upload starts; reuse both to retry an upload whose result you never saw.
volcano cloud sandboxes templates deploy data-analyst --path ./sandbox --memory 1024 --ports 8080

# The image is built and validated, and port 8080 has to accept connections,
# before the template becomes active
volcano cloud sandboxes deployments get <template-id> <deployment-id>
volcano cloud sandboxes deployments logs <template-id> <deployment-id> --region us-east-1

# New sessions use the active image. Sessions already running keep theirs.
volcano cloud sandboxes run --template <template-id>

# Ship a new version of the same template
volcano cloud sandboxes templates deploy data-analyst --path ./sandbox --template <template-id>

# History, and the original source of an activated deployment
volcano cloud sandboxes deployments list <template-id>
volcano cloud sandboxes deployments source <template-id> <deployment-id> > source.tar.gz
```

## What people run in sandboxes

### Answer follow-up questions from saved results

Run an analysis, save its files, and reuse them for the next question instead of starting over.

### Let coding agents test their changes

Write files, run tests, and feed failures back to the agent. Start the app when tests pass and grant a reviewer access to its preview.

### Execute LLM-generated code

Run each snippet in a temporary sandbox that is terminated before the result comes back. Retry with the same request ID without running the code twice.

## Works with the rest of Volcano

- [Manage sessions from a function](https://volcano.dev/features/edge-functions): Run sandbox commands from a function and keep the service key on the server.
- [Retry workflow steps safely](https://volcano.dev/features/durable-functions): Reuse each command’s request ID when a workflow retries a step to avoid running the code twice.
- [Give users their own session access](https://volcano.dev/features/authentication): Grant a signed-in user access to a specific session to run commands, read files, or open its preview.
- [Save results before cleanup](https://volcano.dev/features/file-storage): Copy results out of /workspace before terminating the session. Termination removes its files.

## Frequently asked questions

### How do I run code an LLM writes safely?

Run LLM-generated code in a hosted Volcano Sandbox, where each session has its own isolated VM. Manage sessions with a platform user token, project service key, or full-scope project access token. Grant signed-in users access only to the sessions they need. Local sandboxes from volcano start are Docker containers that share your machine’s kernel, so use hosted sandboxes when you need VM isolation.

### When should I use a sandbox session instead of one-shot execution?

Use a session when commands need to share files or keep a background process running. Use one-shot execution for a single snippet. Volcano terminates its temporary VM before the result comes back.

### What are the memory and time limits for a sandbox?

Hobby sandboxes support up to 1 GiB of memory and a one-hour lifetime; Superagent supports up to 2 GiB and eight hours. The lifetime includes startup and keeps counting while suspended. Hobby allows five concurrent sessions, and Superagent has a 100-session safety ceiling.

### How much does sandbox code execution cost?

Sandbox runtime is configured memory multiplied by running time, with 5 GB-hours included monthly on Hobby and 20 on Superagent per account. One GB-hour is 1 GiB running for one hour, including idle time. Superagent overage costs 25 credits per 5 GB-hour block; Hobby has no overage. Suspended time is free, and snapshots are included.

### Can I install custom dependencies in a sandbox?

Deploy a custom sandbox template to include the dependencies your agent needs. Put a Dockerfile fragment and its files in a directory, without FROM, ENTRYPOINT or USER, because Volcano supplies the base image and supervisor. Deploy it with the CLI as an archive of up to 32 MiB, and Volcano builds and validates the image before activating it. Existing sessions keep their original image.

### Can my AI agent run code in a sandbox through MCP?

An agent can run code and manage Volcano Sandboxes through MCP with a full-scope project access token. Start a session or run a one-shot command, read and write files, and suspend, resume, or terminate sessions. A read-only token can inspect sessions and read files. Issue port credentials and user grants from your backend.

## Get started

Give your agent a sandbox Create a free account at https://volcano.dev/signup, or have your coding agent follow the setup playbook at https://volcano.dev/setup.md.
