# Sandboxes

> Create isolated containers from Python, run commands in them, move files and snapshot their filesystem.

Source: https://nodus-platform-site.pages.dev/docs/guides/python/sandboxes/
Build revision: 211ad9f836655b1c3a2668c4693e442471f28614

A Sandbox is an isolated, long-running container for agents and untrusted code. You drive it with commands and file operations; it stops when idle and starts again on the next command.

examples/python/sandbox/main.py

```python
"""Create a Sandbox, run commands in it, move files and delete it.

Run it with `python examples/python/sandbox/main.py`.
"""

import nodus


def main() -> None:
    sb = nodus.Sandbox.create(
        cpu=1,
        memory="2Gi",
        idle_timeout="5m",
        max_cost=1,
    )
    try:
        p = sb.exec("python", "-c", "print(6 * 7)")
        print("stdout:", p.stdout.read().strip(), "exit:", p.wait())
        with sb.open("/workspace/notes.txt", "w") as f:
            f.write("written from the SDK\n")
        print(sb.exec("cat", "/workspace/notes.txt").stdout.read(), end="")
    finally:
        sb.terminate()


if __name__ == "__main__":
    main()
```

## Create

```python
sb = nodus.Sandbox.create(
    name="agent-1",                      # optional; creating the same name again reconnects
    image="nodus/agent-tools",           # the default: Python 3.12, Node 22, git
    cpu=2, memory="4Gi",
    timeout="24h", idle_timeout="5m", on_idle="stop",
    network=nodus.Egress.open(),         # outbound access; the default is nodus.Egress.deny()
    max_cost=5,
)
```

`create` returns as soon as the Sandbox is admitted; commands wait for it to start. Egress is denied unless you open it. `nodus.Sandbox.from_name("agent-1")` reconnects and starts it again if you stopped it.

Not available yet

These arguments raise `nodus.errors.Unsupported` before anything is sent: `volumes=`, `ports=` (and `sb.tunnels.open()`), `init=`, `service=`, `gpu=` and an allow-list egress (`nodus.Egress.allow(...)`). `image=` takes a published image name, not an `nodus.Image` that Nodus builds. `secrets=[...]` is sent when you set it, and raises `Unsupported` while the API does not accept secrets on a Sandbox.

## Run commands

```python
p = sb.exec("python", "-c", "print(6 * 7)")
print(p.stdout.read())       # everything the process wrote to stdout
assert p.wait() == 0         # the exit code

p = sb.exec("pip install requests && python app.py")   # one string runs under /bin/sh -c
for chunk in p.stdout:       # stream output as it arrives
    print(chunk, end="")

p = sb.exec("bash", pty=True)
p.write("ls\n"); p.resize(40, 120); p.signal("SIGINT")
```

Every command is recorded as a Process, and its output is kept, so a reader that reconnects continues where it stopped. `p.stdin.write(...)` and `p.stdin.write_eof()` feed input; `p.cancel()` stops the process.

## Files

```python
with sb.open("/workspace/notes.txt", "w") as f:
    f.write("hi")
print(sb.files.read("/workspace/notes.txt"))
print(sb.files.list("/workspace"))
```

## Stop, start and snapshot

```python
sb.stop()            # saves the filesystem; compute billing stops, the saved files count as storage
sb.start()
image = sb.snapshot_filesystem()             # Beta: an Image of the current filesystem
sb.terminate()       # deletes it
```

Beta

`snapshot_filesystem()` is Beta. Memory is not captured: processes start fresh in a Sandbox created from the image. A Sandbox cannot start from the snapshot Image yet.
