On Runtime, 2,000 workbook analyses cost about $1.92 a month on 2 vCPU, 4 GiB sandboxes. This is at the rates in force on
26 October 2026. The sandbox is billed only for the CPU the model's code uses. pandas 2.1.4 and
NumPy come in the default image. With network: { internet: false }, the data in a customer's
workbook cannot leave the machine.
The short answer
Build a small image with openpyxl once. Then give each workbook a sandbox of its own:
TypeScriptimport { readFile, writeFile } from "node:fs/promises";import { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "sheets", recipe: { pip: ["openpyxl"] } }); // onceawait using sbx = await runtime.sandboxes.create({ image: "sheets", network: { internet: false } });await sbx.files.write("/workspace/in/budget.xlsx", await readFile("budget.xlsx"));// Every sheet at once, as a dict of data frames the model can inspect.await sbx.interpreter.run( "import pandas as pd\nbook = pd.read_excel('in/budget.xlsx', sheet_name=None)",);const shapes = await sbx.interpreter.run("{name: df.shape for name, df in book.items()}");console.log(shapes.results[0]?.data["text/plain"]);// ... the model's cells run here, each one sees `book` ...await sbx.interpreter.run( "import os\nos.makedirs('out', exist_ok=True)\n" + "with pd.ExcelWriter('out/summary.xlsx') as w:\n" + " for name, df in book.items():\n" + " df.describe().to_excel(w, sheet_name=name[:31])",);await writeFile("summary.xlsx", await sbx.files.read("/workspace/out/summary.xlsx"));Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(name="sheets", recipe={"pip": ["openpyxl"]}) # oncewith runtime.sandboxes.create(image="sheets", network={"internet": False}) as sbx: with open("budget.xlsx", "rb") as file: sbx.files.write("/workspace/in/budget.xlsx", file.read()) sbx.interpreter.run("import pandas as pd\nbook = pd.read_excel('in/budget.xlsx', sheet_name=None)") shapes = sbx.interpreter.run("{name: df.shape for name, df in book.items()}") print(shapes["results"][0]["data"]["text/plain"]) sbx.interpreter.run( "import os\nos.makedirs('out', exist_ok=True)\n" "with pd.ExcelWriter('out/summary.xlsx') as w:\n" " for name, df in book.items():\n" " df.describe().to_excel(w, sheet_name=name[:31])" ) with open("summary.xlsx", "wb") as file: file.write(sbx.files.read("/workspace/out/summary.xlsx"))pandas reads .xlsx files with openpyxl, which is why the image adds it. The
interpreter keeps book in memory between cells. The model can therefore look
at the columns, clean them and summarize them without reading the file again. A
CSV needs nothing extra: pd.read_csv works in the default image.
Formulas, values and what the model sees
A spreadsheet is more than a table. These are the cases that cause agents problems, and how to handle each one in the sandbox:
| In the workbook | What to do |
|---|---|
| Several sheets | sheet_name=None returns every sheet as a data frame, keyed by name |
| Header rows above the table | header= and skiprows= in read_excel; let the model look at the first rows first |
| Formulas | openpyxl's load_workbook returns the formula text by default |
| The computed value of a cell | load_workbook(path, data_only=True) returns the value Excel stored when it last saved |
| Merged or styled cells | Edit the workbook with openpyxl instead of pandas, so formatting is kept |
| A chart for the user | Plot with matplotlib; the interpreter returns it as a PNG |
Tell the model which of the two it is reading. Then it never reports the text
=SUM(B2:B40) as a figure. Keep the formulas when it writes the workbook back.
Why a sandbox and not your own server
Spreadsheets arrive from customers, and a model writes the code that reads them. Both are untrusted. In the sandbox:
- The code runs in a Firecracker microVM with its own kernel. It does not run in a container that shares your server's kernel.
- The data stays in.
internet: falserefuses every outbound connection. Root inside the sandbox cannot turn it back on. - Each cell has a time limit. Pass
timeoutMstointerpreter.run. A timeout returns as a result, not as a hung worker. - Nothing is left behind. The sandbox is deleted at the end of the block, and with it every copy of the workbook.
Large workbooks and many files
files.write sends large files in parallel 1 MiB chunks. Each chunk is checked
by SHA-256, and an upload resumes after a dropped connection. The only size limit
is the disk, which diskMiB raises. A folder of files goes in one call with
files.upload(localDir, "/workspace/in"). For workbooks kept in a bucket, mount
the bucket read-only as a directory. The sandbox never holds the bucket's key
(mount your own bucket).
What a spreadsheet agent needs
| Need | How Runtime covers it |
|---|---|
Read .xlsx and .csv |
pandas 2.1.4 in the default image; openpyxl in a one-line recipe image |
| State across the model's steps | Interpreter variables persist between cells |
| Return an edited workbook | files.read gives the bytes of any file the code wrote |
| Charts | matplotlib figures come back as PNG results |
| Customer data kept private | Internet off per sandbox, enforced on the host |
| A fresh machine per file | A new microVM per file, from a machine started ahead of time for the common shapes |
| Code that loops forever | timeoutMs per cell; timeoutSeconds bounds the sandbox |
What it costs
Take 2,000 workbooks a month. Each keeps a 2 vCPU, 4 GiB sandbox running for 90 seconds while the model works through it. The cells use 30 CPU-seconds:
- CPU
- 2,000 × 30 s / 3,600 × $0.025
- $0.42
- Memory
- 2,000 × 90 s / 3,600 × 4 GiB × $0.0075
- $1.50
- Total
- $1.92
That is about a tenth of a cent per workbook. The sheets image is stored free as one
of the first three images an account without credit keeps free. Otherwise it costs $0.08 per GB a month. Runtime charges $0.025 per vCPU-hour of measured CPU and
$0.0075 per GiB-hour of memory. It stores images at $0.08 per GB per 30-day
month (pricing).
Start
Terminalnpx withruntime sandboxes run -- python3 -c 'import pandas; print(pandas.__version__)'The first run opens a browser page to approve the connection. After that,
runtime sandboxes run-code <id> clean.py runs a script as an interpreter cell
from a terminal (CLI).
Related: data analysis agent, chart generation, SQL analysis agent, turn off sandbox internet.
Sources
- pandas.read_excel: openpyxl is the engine for
.xlsxfiles, read 26 October 2026. - openpyxl tutorial:
data_onlyreturns the formula or the value Excel last stored, read 26 October 2026.
Facts on this page were checked on 26 October 2026.