Skip to content

Commands, files and terminals

Making a sandbox from any image, running commands and reading their output, reading and writing files, and terminals.

עודכן ב-

הדף הזה עדיין לא תורגם לעברית: הנה הוא באנגלית.

Making a sandbox

POST /v1/sandboxes makes a sandbox; every field may be left out.

Field What it is
image Any OCI image, public or private (python:3.12, ghcr.io/acme/api:1.4). Without one, the platform’s default image (below).
image_pull_secret For a private image: the name of a secret whose value is the registry’s username:password. It is used to pull the image and is nowhere in the sandbox.
snapshot or template Start from a snapshot or a template instead of an image. At most one of the three.
name 1 to 63 lower-case letters, digits and hyphens. Anywhere an id is taken, the name is too.
env, metadata Environment variables (up to 256 KiB in all); up to 64 labels, which usage can be grouped by. The label product is the platform’s, and a create or a change that sets it is refused (400 reserved_metadata).
limits The size: {vcpus, memory_bytes}, memory an even number of MiB (a whole number of the 2 MiB pages a machine’s memory is loaded in) and at least 128 MiB, never larger than your plan allows. Other memory is refused (400 invalid_field).
sleep_after_seconds How long it stays awake when idle: 30 unless you say, at least 1, null for never. See sleep and wake.
sleep_notice_ms, sleep_hold_max_ms How long before it sleeps its programs are told, and how long they can keep it awake by themselves: see keeping it awake from inside.
expires_at, delete_after_idle_ms When it is deleted; or how long it may sleep before it is deleted.
volumes, drives, public_ports, egress Drives and volumes mounted at paths, ports anyone may open, its network rules. A volume with copy: true that is new is given what the image has at its path when it is first mounted, as Docker gives a new named volume.
start_command, start, ready A service started when the machine boots, and the check that says it is up (below).
init "systemd": a whole system, the image’s own systemd its PID 1 (below). Without it, the platform’s init.
runtime Limits of its processes, kernel settings, file systems in memory, its resolver and the size of /dev/shm, as an app version’s runtime settings are. Without them, open files are 1,024, raised to 524,288 at the most, as under Docker.
awake_ports, connection_idle_seconds Ports whose connections, upgraded through a link (a WebSocket), keep it awake while they are open, and how long one may carry nothing before it is closed: see awake while a client is connected.
hostname, stop The name its machine has, for good, in place of its id; how its service is stopped before a restart or a delete: {signal, grace_ms} (the image’s STOPSIGNAL, else SIGTERM; 10 seconds before it is killed, ten minutes at the most).
project_network true: it is on the project’s private network from before it runs anything, at its project_address.
checkpoint {every_seconds}: checkpoints while it is awake, so that it goes on with its processes when its machine is lost. None unless you say.
region na, eu or ap: where it is made. Without it, the region of the control plane. See regions.

The first sandbox made from an image is starting while the platform pulls the image and saves a template of it; calls sent to it wait until it is ready. Every later sandbox from that image is a copy of the template, taken from a pool of copies that are already running.

Without limits, a sandbox has the size of the machine’s base template, and never more than your plan’s largest: 2 vCPU ו-4 GiB on Free, 8 vCPU ו-16 GiB on Paid. A larger limits than the plan allows is refused (403 plan_size_exceeded). A sandbox’s root disk is 8 GiB.

The default image

Debian 12 with Node 24, Python 3.11 (pip, venv, uv), Go, Rust, Java 25 with Maven, and everyday tools (ripgrep, jq, sqlite3, rsync, dig, sudo). Commands run as root from /root; a second account, user, has sudo without a password. Nothing is started in it and no port listens.

A service that starts with the machine

With start_command (or start: true, which runs the image’s own ENTRYPOINT and CMD) and a ready check, the platform starts the service once, waits until it is ready, and saves that as the template. Every sandbox made with the same settings is a copy, with the service already running and its memory shared until the sandbox changes it.

What a program does before the template is saved is the same in every sandbox made from it: keys, tokens, cookies, ids it generated, the state of its random number generator. A start command must not make anything that identifies a user or a session before it is ready; make those on first use, or in a command run after the sandbox is made.

A whole system: systemd

With init: "systemd", a sandbox is a whole machine: the image’s own systemd is its PID 1, and the platform’s agent is one of its services. You install packages, start services with systemctl, use cron and the journal, and log in by SSH, as on a server.

glac sandboxes create --name box --init systemd
glac sandboxes exec box -- systemctl status
  • Without an image, it is the platform’s Ubuntu 24.04 (below). Any image with systemd works; one without it fails to build (invalid_image).
  • What runs is what its units say. A create that gives init with start, start_command or ready is refused (400 invalid_start), and so is init on a sandbox made from a snapshot or a template, which is what it was. Another value is 400 invalid_field. POST /v1/run takes init too, and a sandbox says its own (init: systemd, or null for the platform’s init).
  • Its own machine ID. /etc/machine-id (and D-Bus’s copy) is the sandbox’s own, given when its machine is made and kept through sleeps, wakes and moves; one made from its snapshot, and each fork, has its own. Its journal is kept under it, on its disk.
  • The platform keeps the network, the resolver, the clock and the serial console: the units that would change them (systemd-networkd, NetworkManager, systemd-resolved, timesyncd, chrony, the getty on the serial console, systemd-firstboot) are masked at each boot. A unit of the same name in the image’s /etc/systemd/system overrides the mask, as it overrides any.
  • Sleep. It sleeps when it is idle, as any sandbox does: systemd’s own timers do not keep it awake, and a timer unit with Persistent=true runs what it missed when the sandbox wakes. cron runs only while the sandbox is awake, and its run every minute can put off its sleep by up to a minute; give what must run on a schedule a timer unit.
  • Commands run through the platform (exec, run, terminals) are processes of the agent’s service, not a login session: systemctl --user works in an SSH login to the machine’s own server, not there. The sandbox’s env and secret_env are those commands’ environment; systemd’s services have what their units give them (Environment=).
  • reboot and poweroff end the machine, as in any sandbox.

The platform’s Ubuntu image is Ubuntu 24.04 with systemd, D-Bus, an OpenSSH server, cron and the tools a person or an agent reaches for first (curl, git, jq, python3 with venv, rsync, sudo, htop, dig, zip and the like); other tools come with apt. Commands run as root, and an account user has sudo without a password. Its SSH server takes keys alone, and each machine makes its own host keys when the server first starts; from outside you reach a sandbox by the platform’s SSH gateway, and the machine’s own server is for what is beside it (a port forwarded to it, another sandbox on the project’s network). The timers that would wake it every day for nothing of yours (apt’s, motd-news, fstrim, dpkg’s backups) are masked, and its journal is kept on its disk.

Running commands

Call What it does
POST /v1/sandboxes/{id}/run Runs a command and waits for it. Returns the exit code, stdout and stderr.
POST /v1/sandboxes/{id}/exec Starts a command and returns its id at once (exe-…). Its output is read with GET …/exec/{exec}/output, which can follow it.
POST /v1/run Makes a sandbox, runs one command and deletes it: the sandbox lives as long as that request.

A command given as a string is run by sh -c; a list is run as it is, without a shell, its program found along the PATH of the command’s own environment (the image’s, with what the call adds), as sh -c finds it, so a program in a directory only the image adds (/usr/local/cargo/bin, /opt/conda/bin) is found. It runs as root unless you give user, in cwd, with env added to the sandbox’s.

glac sandboxes exec web 'ls /srv | wc -l'           # one argument: a line for sh -c
glac sandboxes exec web -- ls -la /srv              # several: a program and its arguments
tar c . | glac sandboxes exec web tar x -C /srv     # standard input goes to the command
cmd=$(glac sandboxes exec web --detach -- sh -c 'while true; do date; sleep 1; done')
glac sandboxes logs web "$cmd"                      # what it printed so far (--follow: until it ends)
glac sandboxes kill web "$cmd" --signal INT
  • Output is kept with a position for every byte, the last 16 MiB of each command, so a reader that was cut off goes on where it was. A command never waits for a slow reader: write large output to a file and copy it out.
  • A command belongs to the sandbox, not to the connection: glac sandboxes exec picks up where it was after a dropped connection, and the first Ctrl-C goes to the command (a second leaves it running).
  • Exit codes. glac run, glac sandboxes exec and glac sandboxes shell exit with the command’s code, and with 125 when what failed was not the command. The SDKs return the code as a result, not as an error.

Files

/v1/sandboxes/{id}/files reads, writes, lists, moves and deletes files, as the user that runs commands (or another, with user), and sets a file’s mode, length or time of last modification (PATCH with mode, size_bytes, modified_at; set_attributes in the SDKs). A write replaces the whole file at once, unless it gives an offset; a reader sees the old content or the new, and a write whose content stops half way leaves the file as it was. A file of any length is read or written in one call: its bytes pass through as they come, nothing holds the whole file on the way, and a read says its length first. The SDKs’ upload, download and read_stream (readStream) do it from and to local files.

glac sandboxes cp -r ./src web:/srv/src              # in
glac sandboxes cp web:/var/log/app.log .             # out
glac sandboxes cp web:/etc/os-release -              # to standard output
sbx.files.write("/srv/config.json", '{"debug": true}')   # makes the directories above it
print(sbx.files.list("/srv"))
data = sbx.files.read("/srv/config.json")

Terminals

glac sandboxes shell web opens a terminal: a shell, or the command given (glac sandboxes shell web htop). Enter, then ~. leaves it running; --join exe-… comes back to it. An open terminal does not keep the sandbox awake: when it has slept, the next key wakes it.

With the API, a terminal is a command started with tty: {cols, rows} (POST …/exec) and a WebSocket to …/exec/{exec}/tty, which carries its input, output and size. A browser cannot set headers on a WebSocket, so it passes a token with the tty scope in ?sandbox_token=. The console’s terminal works this way. The SDKs have sbx.terminal().

Code interpreters, agents and desktops

The platform has images for stateful code execution, for coding agents, and for a desktop whose screen a program can see and drive. The SDKs have calls for them: sbx.run_code(…), sbx.agent("claude") and Desktop(sbx) in Python. See the Python SDK page.

ניווט

הקלידו כדי לחפש…

↑↓ ניווט↵ בחירהEsc סגירה