# Quickstart This guide takes you from zero to a sandbox running real code in about five minutes. By the end you'll have run Python in a stateful interpreter session (variables persist between calls, like a notebook), run shell commands, worked with files, streamed output from a long-running process, and paused / resumed a session. > **Get started** > > Sandboxes are free to start. Enable them in one click from the [Sandboxes console](https://orkestr.eu/sandbox), then mint a token with a sandbox scope to use the SDK. ## 1. Install the SDK Pick the language your agent runs in. The Python and JS SDKs ship the same surface; field names are `snake_case` in Python and `camelCase` in JS. **Python:** ```python pip install orkestr ``` **JavaScript:** ```javascript npm install orkestr ``` ## 2. Mint an API token Sign in to the orkestr console, open Settings, and create a new API token scoped to `sandboxes:read` and `sandboxes:write`. Sandbox-scoped tokens cannot reach the rest of the platform - use them in agent runtimes where credentials may end up in stack traces or LLM contexts. Export the token: ```bash export ORKESTR_API_KEY="ork_..." ``` ## 3. Run your first sandbox The `code-interpreter` template gives you a persistent Python session: every `run_code` call executes in the same interpreter, so variables, imports and dataframes carry over between calls - and results come back rich (text, HTML tables, PNG charts and parsed chart data), with exceptions as structured data instead of stderr text. pandas, NumPy and matplotlib are preinstalled. The `with` / `withTemp` pattern auto-terminates the sandbox on exit, which keeps your bill bounded if the agent loop crashes before it gets to call terminate explicitly. **Python:** ```python from orkestr import Sandbox with Sandbox.create(template="code-interpreter") as sbx: sbx.run_code("import pandas as pd; df = pd.DataFrame({'eur': [120, 80, 45]})") # A separate call, same interpreter: df is still there. execution = sbx.run_code("df.sum()") print(execution.text) # eur 245 ``` **JavaScript:** ```javascript import { Sandbox } from "orkestr"; await Sandbox.withTemp({ template: "code-interpreter" }, async (sbx) => { await sbx.runCode( "import pandas as pd; df = pd.DataFrame({'eur': [120, 80, 45]})", ); // A separate call, same interpreter: df is still there. const execution = await sbx.runCode("df.sum()"); console.log(execution.results[0]?.text); // eur 245 }); ``` That two-calls-one-session shape is the whole trick: an agent can load data once and keep analyzing it across turns. Charts, isolated contexts, and error semantics are covered in the full [Code interpreter](https://orkestr.eu/docs/sandboxes/code-interpreter) guide. ## 4. Run shell commands Alongside the interpreter, every sandbox runs shell commands with `exec` - builds, scripts, servers, package installs. Both work in the same sandbox, and `exec` is available on every template. **Python:** ```python sbx.files.write("/workspace/main.py", "print(sum(range(1_000_000)))") result = sbx.exec("python /workspace/main.py") print(result.stdout) # 499999500000 print(result.duration_ms) # ~120 ``` **JavaScript:** ```javascript await sbx.files.write( "/workspace/main.py", "print(sum(range(1_000_000)))", ); const result = await sbx.exec("python /workspace/main.py"); console.log(result.stdout); // 499999500000 console.log(result.durationMs); // ~120 ``` ## 5. Stream long-running output For commands that take longer than a few seconds, use streaming so the SDK doesn't hold all the bytes in memory and you can react to output as it arrives. **Python:** ```python for chunk in sbx.exec_stream("python long_task.py"): if chunk.stream == "stdout": print(chunk.data, end="", flush=True) if chunk.is_final: print(f"exit={chunk.exit_code} in {chunk.duration_ms}ms") ``` **JavaScript:** ```javascript for await (const chunk of sbx.execStream("python long_task.py")) { if (chunk.stream === "stdout") { process.stdout.write(chunk.data); } if (chunk.exitCode !== undefined) { console.log(`exit=${chunk.exitCode} in ${chunk.durationMs}ms`); } } ``` ## 6. Work with files Every sandbox has a writable `/workspace` directory. Reads and writes go through the SDK as base64 over HTTPS; the SDK handles encoding so you can pass plain strings or bytes. **Python:** ```python # Write sbx.files.write("/workspace/data.json", '{"x": 1}') sbx.files.write_bytes("/workspace/blob.bin", b"\x00\x01\x02") # Read content = sbx.files.read("/workspace/out.txt") raw = sbx.files.read_bytes("/workspace/blob.bin") # List for entry in sbx.files.list("/workspace"): print(entry.name, entry.is_dir, entry.size) ``` **JavaScript:** ```javascript // Write await sbx.files.write("/workspace/data.json", '{"x": 1}'); await sbx.files.writeBytes( "/workspace/blob.bin", new Uint8Array([0, 1, 2]), ); // Read const content = await sbx.files.read("/workspace/out.txt"); const raw = await sbx.files.readBytes("/workspace/blob.bin"); // List for (const entry of await sbx.files.list("/workspace")) { console.log(entry.name, entry.isDir, entry.size); } ``` ## 7. Pause and resume across requests Long-lived agent sessions can pause a sandbox between turns to stop the compute meter and resume from the same state minutes or hours later. `pause()` returns the sandbox id; persist it wherever your agent keeps state and pass it back to `Sandbox.resume()`. This includes interpreter sessions: a paused code-interpreter sandbox resumes with its kernel and every variable exactly where you left them. **Python:** ```python sbx = Sandbox.create(template="node-22", network="restricted") sandbox_id = sbx.pause() # Persist sandbox_id somewhere (Redis, DB, agent state). # Later, anywhere: sbx = Sandbox.resume(sandbox_id) result = sbx.exec("node server.js --status") ``` **JavaScript:** ```javascript const sbx = await Sandbox.create({ template: "node-22", network: "restricted", }); const sandboxId = await sbx.pause(); // Persist sandboxId somewhere (Redis, DB, agent state). // Later, anywhere: const resumed = await Sandbox.resume(sandboxId); const result = await resumed.exec("node server.js --status"); ``` > **Snapshot retention** > > Snapshot retention is tier-capped (free: 1, payg: 10, enterprise: 50). Calling `pause()` over the cap raises `SnapshotCapReached`; terminate or resume an older snapshot first. A paused sandbox is also not kept forever: it expires after 7 days on the free tier and 30 days with a card on file (never on enterprise). The exact deadline is returned as `paused_expires_at` on the sandbox, and every resume restarts the clock. ## Next steps - [Code interpreter](https://orkestr.eu/docs/sandboxes/code-interpreter) - rich results, charts as data, isolated contexts, error semantics - [Cookbook](https://orkestr.eu/docs/sandboxes/cookbook) - copy-paste recipes for agent loops, installs, and parallel fan-out - [Python SDK reference](https://orkestr.eu/docs/sandboxes/python-sdk) - every method, parameter, and error class - [JS SDK reference](https://orkestr.eu/docs/sandboxes/js-sdk) - the same surface for JS / TS - [REST API reference](https://orkestr.eu/docs/sandboxes/api-reference) - hit the wire format directly from any language