> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boxd.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent sandboxes

> Give your agent its own computer. Full root, public HTTPS URL, persistent disk. Fork to recover.

Hand your agent a full Linux machine and walk away. Each task runs in its own boxd VM with root, internet, a public HTTPS URL, and a 100 GB disk that survives whatever the agent does to it. If a run goes sideways, fork the pre-task state and try again.

## How it works

Every boxd VM is a KVM microVM with its own kernel, network stack, and disk. Not a container. The agent can run Docker, install kernel modules, edit `/etc`, restart `systemd`, open ports, and break the OS without taking down anything else.

Fresh boots take \~30ms. Forks land in \~160ms and inherit the parent's exact disk, processes, and memory. Resume from suspend is sub-millisecond. So the loop "snapshot, hand off, fork on retry, destroy when done" actually feels instant.

Inside the VM the agent has the `boxd` CLI on its PATH, already authenticated. It can create siblings, exec into them, manage proxies, and list VMs without needing a key or a token. JSON output everywhere so the agent can parse what it ran. The SDKs work the same way in there — `new Boxd()` in TypeScript, `Boxd()` in Python, no API key and no configuration.

That's the whole pitch. The setup is one command.

## Run a task

Boot a sandbox, hand a job to Claude Code non-interactively, get a structured result back:

<Tabs>
  <Tab title="CLI">
    ```bash theme={"theme":"github-dark"}
    boxd machine new task-1 --json

    RESULT=$(boxd machine exec task-1 --json \
      'claude -p --output-format json "Build a Flask API on port 8000 with /health" \
       --dangerously-skip-permissions 2>/dev/null')

    SESSION_ID=$(echo "$RESULT" | jq -r '.output' | jq -r .session_id)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"github-dark"}
    import { Boxd } from "@boxd-sh/sdk";

    const boxd = new Boxd();
    const machine = await boxd.machines.create({ name: "task-1" });
    await boxd.machines.waitUntilReady(machine.id);

    const result = await boxd.machines.exec(machine.id, {
      command: [
        "claude", "-p", "--output-format", "json",
        "Build a Flask API on port 8000 with /health",
        "--dangerously-skip-permissions",
      ],
    });
    console.log(result.stdout);   // structured Claude output (includes session_id)
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"theme":"github-dark"}
    from boxd import Boxd

    boxd = Boxd()
    machine = boxd.machines.create("task-1")
    boxd.machines.wait_until_ready(machine.id)

    result = boxd.machines.exec(machine.id, [
        "claude", "-p", "--output-format", "json",
        "Build a Flask API on port 8000 with /health",
        "--dangerously-skip-permissions",
    ])
    print(result.stdout)   # structured Claude output (includes session_id)
    ```
  </Tab>
</Tabs>

The agent's working directory is on a 100 GB disk that persists across reboots. The build is live at `https://task-1.boxd.sh` the moment a port opens. To take over interactively, connect and resume the session (`<session_id>` comes from the result above):

```bash theme={"theme":"github-dark"}
boxd connect task-1           # or: ssh task-1.boxd
claude --resume <session_id>
```

When you're done, `boxd machine remove task-1 -y` and the disk goes with it.

## Patterns

### Fork before risky ops

Snapshot the VM before the agent does something destructive. If the run fails, fork the parent again and retry. The parent never changes.

```bash theme={"theme":"github-dark"}
boxd machine fork task-1 task-1-attempt-2 --json
boxd machine exec task-1-attempt-2 'claude -p "Apply the schema migration" --dangerously-skip-permissions'
```

### Fan out across many VMs

Run the same task in parallel and pick the best output. Every result has its own URL.

```bash theme={"theme":"github-dark"}
for i in 1 2 3; do boxd machine new try-$i --json & done; wait
for i in 1 2 3; do
  boxd machine exec try-$i "claude -p \"Implement option $i\" --dangerously-skip-permissions &"
done
# Results land at https://try-1.boxd.sh, try-2, try-3
```

### Destroy on completion

Wire the destroy step into your PR-close hook or the agent's exit path. You're billed for what you run, so kill VMs you don't need.

## FAQ

<AccordionGroup>
  <Accordion title="What stops an agent from breaking out?">
    The microVM boundary is the same one your laptop's hypervisor uses. The agent has root inside its VM, no path to the host or to other VMs. Internet egress is the only shared surface.
  </Accordion>

  <Accordion title="How many sandboxes can I run at once?">
    Ten VMs by default, extendable on request. Each gets 2 vCPU, 8 GiB RAM, 100 GB disk.
  </Accordion>

  <Accordion title="Can the agent install kernel modules or run Docker?">
    Yes. Real kernel, real `systemd`, real Docker. Nesting works because there's no container in the way.
  </Accordion>

  <Accordion title="How do I recover a run that went wrong?">
    If you forked from a golden, just `boxd machine remove` the bad fork and fork again. The golden is untouched.
  </Accordion>
</AccordionGroup>

## Next

<Columns cols={2}>
  <Card title="Fork from a golden" icon="https://mintcdn.com/azin/Ax1V0serIwQf0x_2/images/icons/copy.svg?fit=max&auto=format&n=Ax1V0serIwQf0x_2&q=85&s=f3623fe516eebf87b33b3a1022852286" href="/cloud-dev-boxes/fork-from-a-golden" width="16" height="16" data-path="images/icons/copy.svg">
    Warm copies of your app in \~160ms. The sandbox source.
  </Card>

  <Card title="Fix-on-issue loop" icon="https://mintcdn.com/azin/Ax1V0serIwQf0x_2/images/icons/bug.svg?fit=max&auto=format&n=Ax1V0serIwQf0x_2&q=85&s=793936d309dacb75c015231f4754aa3e" href="/agents/fix-on-issue" width="16" height="16" data-path="images/icons/bug.svg">
    The full end-to-end agent loop on GitHub issues.
  </Card>
</Columns>
