Sandboxes
Start an isolated Linux machine, run commands and move files in and out, billed by the second.
A sandbox is a short-lived Linux machine for running code you don't want on your own servers: code a model wrote, a user's upload, a build. It starts in seconds and stops on its own when its time is up.
Start a sandbox
import noclick
with noclick.Sandbox.create(image="python", timeout_s=600) as sb:
result = sb.exec("python -c 'print(21 * 2)'")
print(result.stdout) # 42Leaving the with block stops the sandbox. Without it, call sb.terminate(), or let it stop at expires_at.
| Option | Default | Range |
|---|---|---|
image | "python" | "python" or "node" |
timeout_s | 600 | 10 to 3,600 seconds |
cpu | 1 | 0.25 to 2 cores |
memory_mb | 2,048 | 512 to 4,096 |
network | False | True allows outbound internet access; a list of up to 50 hosts allows only those (below) |
region | your account's default region | us-east, us-west, eu or ap (Regions) |
A sandbox's lifetime and region are fixed when it's created; nothing can extend or move it. With no region and no account default, it runs wherever NoClick has capacity and its region is None.
Run commands
result = sb.exec("ls -la /workspace")
print(result.exit_code, result.stdout, result.stderr)
sb.exec(["python", "script.py", "--input", "data.csv"]) # an argument list is quoted for youCommands run with bash in /workspace. A command that exits non-zero isn't an error: check result.ok or result.exit_code. A command is stopped after 60 seconds by default; pass timeout_s for up to 90.
Run long commands in the background
For anything longer, background=True returns an operation straight away. A background command can run for up to an hour, but it has to finish before the sandbox stops, so give the sandbox room:
with noclick.Sandbox.create(timeout_s=3600) as sb:
build = sb.exec("make all", background=True, timeout_s=1800)
result = build.wait()
print(result.exit_code)A timeout_s longer than the sandbox has left is refused with noclick.InvalidRequest.
Move files
sb.files.write("/workspace/data.csv", csv_bytes) # bytes, or text as UTF-8
report = sb.files.read("/workspace/report.pdf") # bytesA file is at most 16 MB each way.
Mount volumes and pass secrets
volumes mounts a volume read-write at a path, up to 5, so what the sandbox writes there outlives it: the sandbox sees each volume as it was when it started, and what it writes is saved every few seconds while it runs, and all of it when it ends. secrets puts each key of a secret (up to 20, a later one's key winning) in the environment of every command; the sandbox keeps the values it started with, and its secret_ids lists them:
data = noclick.Volume.from_name("datasets", create_if_missing=True)
openai = noclick.Secret.from_name("openai")
with noclick.Sandbox.create(volumes={"/data": data}, secrets=[openai], network=True) as sb:
sb.exec("python summarize.py --in /data/raw --out /data/summaries")Reach only some hosts
network also takes a list of up to 50 hosts, and the sandbox reaches only those: "pypi.org", or "*.example.com" for a domain and every name under it (example.com itself included). It suits code you don't trust with the whole internet but that needs its packages:
with noclick.Sandbox.create(image="python", network=["pypi.org", "files.pythonhosted.org"]) as sb:
sb.exec("pip install pandas")A host is reached over HTTPS on port 443, by its name, and nothing else gets out: an HTTPS connection to another host is reset at once (Connection reset by peer), and plain http://, SSH, a database port or UDP, even to a listed host, gets no answer, so the client waits out its own timeout. Point package managers at their https:// mirrors. An entry is a host alone: a scheme, a path, a port or an IP address raises noclick.InvalidRequest, as does "*" (that's network=True).
Two things a list doesn't do. It limits connections, not name lookups, so code can still resolve any name. And it bounds where code connects, not as whom: a host you allow is reachable with anyone's account there. A host on a shared edge that picks the site by the request's Host header (some CDNs and app platforms) lets code reach every site behind that edge, so list the services you mean.
An agent's own shell takes the same list: network= on the agent.
Limits and billing
For agents that should always be up, a machine runs them at a flat monthly price instead.
An account runs up to 10 sandboxes and 4 background commands at a time; more raises noclick.QuotaExceeded. A sandbox is billed per second while it runs, and counts toward the spend cap of the user it was created for.
It costs what its provider charges for the CPU and memory it reserves: $0.141912 an hour for each core of cpu and $0.024012 an hour for each 1,024 of memory_mb, so the default 1 core and 2,048 MB is about $0.19 an hour. Pinned to a region, it costs what the provider charges there: 1.15 times as much in eu and ap, 1.75 times in us-east and us-west.
noclick.Sandbox.list(status="live")