Commands, code and files
Run commands in a sandbox buffered, streamed or in the background, run code in a Jupyter kernel, move files in and out, and open a terminal.
All of these need sandboxes:run and a running sandbox. Set SBX to your sandbox's ID in the examples.
Run a command
POST /v1/sandboxes/{sandbox_id}/exec runs a command and, by default, waits for it to exit:
bashcurl -s "https://beta-api.b3os.org/v1/sandboxes/$SBX/exec" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"cmd": "python3 -c \"print(2 + 2)\""}'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const sbx = process.env.SBX!; // a sandbox ID, sbx_...const result = await b3os.sandboxes.exec(sbx, { cmd: 'python3 -c "print(2 + 2)"' });console.log(result.exit_code, result.stdout);
pythonimport osfrom b3os import B3OSb3os = B3OS()sbx = os.environ["SBX"] # a sandbox ID, sbx_...result = b3os.sandboxes.exec(sbx, {"cmd": 'python3 -c "print(2 + 2)"'})if result["object"] == "exec_result": # with "background": True you get the process instead print(result["exit_code"], result["stdout"])
textIn my sandbox, run the test suite with `npm test` in /workspace/app and tell me what failed.
The agent calls sandbox_exec with sandbox_id, cmd and cwd, and reads exit_code, stdout and stderr.
json{ "object": "exec_result", "exit_code": 0, "signal": null, "timed_out": false, "stdout": "4\n", "stderr": "", "stdout_truncated": false, "stderr_truncated": false, "duration_ms": 21.6}
The values are illustrative. cmd as a string runs through /bin/sh -c; as an array (["node", "--version"]) it runs directly. Other fields: cwd (default /workspace), env, stdin (written to the command, then closed), user (user or root) and timeout_ms. A buffered call waits at most 60 seconds and returns up to 1 MiB of each stream; stdout_truncated says when output was dropped. A command killed at its timeout returns timed_out: true and the signal, KILL.
Stream the output
Add ?stream=true (or send Accept: text/event-stream) to get output while the command runs, as exec.stdout and exec.stderr events, then exec.exit with the exit code. A streamed command may run up to an hour.
bashcurl -N -s "https://beta-api.b3os.org/v1/sandboxes/$SBX/exec?stream=true" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"cmd": "for i in 1 2 3; do echo $i; sleep 1; done", "timeout_ms": 60000}'
Run in the background
background: true returns at once with the process, for servers and long jobs:
bashcurl -s "https://beta-api.b3os.org/v1/sandboxes/$SBX/exec" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"cmd": "npm run dev", "cwd": "/workspace/app", "background": true}'# {"object": "process", "pid": 812, "cmd": "npm run dev", "status": "running", ...}
GET /v1/sandboxes/{sandbox_id}/processeslists background processes, running or exited.GET /v1/sandboxes/{sandbox_id}/logsstreams their output aslog.stdoutandlog.stderrevents, thenprocess.exited. It starts with up to 1 MiB of buffered output per process; filter withpid, and passfollow=falseto stop after the buffered output.POST /v1/sandboxes/{sandbox_id}/processes/{pid}/killsendsTERM(orKILL,INT,HUP) to the process and its process group.
Run code in a kernel
Sandboxes from the code-interpreter template have a Jupyter kernel. POST /v1/sandboxes/{sandbox_id}/run_code runs code in it and returns rich results; state persists between calls, like cells in a notebook:
bashcurl -s "https://beta-api.b3os.org/v1/sandboxes/$SBX/run_code" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"code": "import math\nmath.sqrt(2)\n"}'
json{ "object": "run_code_result", "language": "python", "execution_count": 3, "results": [{ "mime_type": "text/plain", "data": "1.4142135623730951", "is_main_result": true }], "stdout": "", "stderr": "", "error": null, "duration_ms": 4.8}
language is python (the default) or javascript. Results carry their MIME type, so plots come back as images and data frames as HTML. A cell that raises returns the exception in error. Other templates answer kernel_unavailable.
Files
| Call | Does |
|---|---|
GET /v1/sandboxes/{sandbox_id}/files?path=/workspace/main.py | Returns the file's bytes |
GET /v1/sandboxes/{sandbox_id}/files?path=/workspace&list=1 | Lists a directory as JSON: name, path, type, size, mode, modified time |
PUT /v1/sandboxes/{sandbox_id}/files?path=/workspace/main.py | Writes the request body to the path, replacing any file; mkdir=1 creates parent directories, mode sets a new file's permissions |
bashcurl -s -X PUT "https://beta-api.b3os.org/v1/sandboxes/$SBX/files?path=/workspace/data/input.csv&mkdir=1" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/octet-stream" \ --data-binary @input.csv
Paths are absolute. A transfer carries at most 64 MiB; for larger files, fetch them from inside the sandbox.
Open a terminal
GET /v1/sandboxes/{sandbox_id}/pty upgrades to a WebSocket attached to a new pseudo-terminal running the login shell, or cmd. Binary frames carry terminal bytes both ways. Text frames carry JSON control messages: send {"type": "resize", "cols": 120, "rows": 40}; the server sends {"type": "exit", "code": 0} before it closes. Pass cols, rows, cmd and cwd as query parameters.
From a browser, get a stream ticket with POST /v1/sandboxes/{sandbox_id}/ticket and open the socket within 30 seconds:
jsconst { ticket } = await (await fetch(`/api/my-backend/ticket?sandbox=${sandboxId}`)).json();const socket = new WebSocket( `wss://beta-api.b3os.org/v1/sandboxes/${sandboxId}/pty?cols=120&rows=40`, ["b3os.v1", `b3os.ticket.${ticket}`],);socket.binaryType = "arraybuffer";
Mint the ticket on your server with your key, never in the browser. The CLI opens the same terminal with b3os sandbox shell.