PandaStack
Use cases

Code interpreter

Replace OpenAI's code-interpreter with a self-hosted Python execution sandbox.

The code-interpreter template runs Python inside a Firecracker microVM. For an agent that analyzes data and returns charts, use a code context — a persistent kernel that keeps state across calls and hands back rich results (images, HTML tables, JSON) as objects, not stdout you have to parse. For one-off commands, use exec / run_code.

create_code_context() starts a long-lived Python kernel (Jupyter-style). Variables and imports persist across run_code calls, and the returned Execution exposes typed results — .png, .html, .json, .text — so a Claude/LangGraph tool can hand a chart straight back to the model.

from pandastack import Sandbox

sandbox = Sandbox.create(template="code-interpreter", ttl_seconds=3600)
ctx = sandbox.create_code_context()

# State persists across cells, exactly like a notebook.
ctx.run_code("import pandas as pd")
ctx.run_code("df = pd.read_csv('/workspace/sales.csv')")

# A DataFrame comes back as an HTML table — no stdout parsing.
ex = ctx.run_code("df.describe()")
print(ex.results[0].html)        # "<table>...</table>"

# A chart comes back as a base64 PNG — no save-to-disk, no second download.
ex = ctx.run_code("""
import matplotlib.pyplot as plt
df['revenue'].plot()
plt.show()
""")
png_b64 = ex.png                 # ready to send to the model or render
import { Sandbox } from "@pandastack/sdk";

const sandbox = await Sandbox.create({ template: "code-interpreter", ttlSeconds: 3600 });
const ctx = await sandbox.createCodeContext();

await ctx.runCode("x = 41");
const ex = await ctx.runCode("import matplotlib.pyplot as plt; plt.plot([1,2,3]); plt.show()");
console.log(ex.png);             // base64 PNG

Each Execution carries:

FieldWhat
resultslist of rich outputs; each has .png / .jpeg / .svg, .html, .markdown, .json, .text, and .chart (the primary image)
stdout / stderrcaptured streams
errorformatted traceback if the cell raised
png / textconvenience: the first image / last text repr produced

Rich output (charts, DataFrame tables) is captured automatically on the code-interpreter template, which bakes IPython, matplotlib, plotly, and pandas. On leaner templates the kernel still works and degrades to a plain-text repr.

Close the context (or kill the sandbox) when done; idle kernels are reaped automatically.

ctx.close()        # or: with sandbox.create_code_context() as ctx: ...

One-shot exec

from pandastack import Sandbox

sandbox = Sandbox.create(template="code-interpreter", ttl_seconds=3600)
result = sandbox.exec('python -c "print(2 + 2)"', timeout_seconds=30)
print(result.stdout)  # "4\n"
sandbox.kill()
import { Sandbox } from "@pandastack/sdk";

const sandbox = await Sandbox.create({ template: "code-interpreter", ttlSeconds: 3600 });
const result = await sandbox.exec('python -c "print(2 + 2)"', { timeoutSeconds: 30 });
console.log(result.stdout);  // "4\n"
await sandbox.kill();
pandastack sandbox create --template code-interpreter --ttl 3600
pandastack sandbox exec <id> --timeout 30 -- 'python -c "print(2 + 2)"'
pandastack sandbox delete <id>
curl -X POST https://api.pandastack.ai/v1/sandboxes \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template": "code-interpreter", "ttl_seconds": 3600}'

curl -X POST https://api.pandastack.ai/v1/sandboxes/<id>/exec \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "python -c \"print(2 + 2)\"", "timeout_seconds": 30}'

curl -X DELETE https://api.pandastack.ai/v1/sandboxes/<id> \
  -H "Authorization: Bearer $PANDASTACK_API_KEY"

This spawns Python fresh each call. Variables don't persist between runs — for that, use a code context instead.

Run Python code

sandbox = Sandbox.create(template="code-interpreter", ttl_seconds=3600)

out = sandbox.run_code("""
x = 42
y = x * 2
print(x, y)
""", language="python")
print(out.stdout)  # "42 84\n"
const sandbox = await Sandbox.create({ template: "code-interpreter", ttlSeconds: 3600 });

const out = await sandbox.runCode(`
x = 42
y = x * 2
print(x, y)
`, "python");
console.log(out.stdout);  // "42 84\n"
pandastack sandbox run-code <id> --language python -- 'x = 42; y = x * 2; print(x, y)'

For shell snippets, use language="shell".

out = sandbox.run_code("python --version", language="shell")
print(out.stdout)

File uploads

sandbox.filesystem.write("/workspace/data.csv", open("./data.csv", "r").read())
result = sandbox.run_code("""
import pandas as pd
df = pd.read_csv('/workspace/data.csv')
print(df.describe())
""", language="python")
print(result.stdout)
import { readFileSync } from "node:fs";

await sandbox.filesystem.write("/workspace/data.csv", readFileSync("./data.csv", "utf8"));
const result = await sandbox.runCode(`
import pandas as pd
df = pd.read_csv('/workspace/data.csv')
print(df.describe())
`, "python");
console.log(result.stdout);
pandastack fs upload <id> --local ./data.csv --remote /workspace/data.csv
pandastack sandbox run-code <id> --language python -- 'import pandas as pd; df = pd.read_csv("/workspace/data.csv"); print(df.describe())'
curl -X PUT "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/data.csv" \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  --data-binary @./data.csv

printf 'import pandas as pd\ndf = pd.read_csv("/workspace/data.csv")\nprint(df.describe())\n' |
  curl -X PUT "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/describe.py" \
    -H "Authorization: Bearer $PANDASTACK_API_KEY" \
    --data-binary @-

curl -X POST https://api.pandastack.ai/v1/sandboxes/<id>/exec \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "python /workspace/describe.py"}'

For larger files, use upload and download helpers:

sandbox.filesystem.upload("./data.csv", "/workspace/data.csv")
sandbox.filesystem.download("/workspace/result.csv", "./result.csv")
await sandbox.filesystem.upload("./data.csv", "/workspace/data.csv");
await sandbox.filesystem.download("/workspace/result.csv", "./result.csv");
pandastack fs upload <id> --local ./data.csv --remote /workspace/data.csv
pandastack fs download <id> --remote /workspace/result.csv --local ./result.csv
curl -X PUT "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/data.csv" \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  --data-binary @./data.csv

curl "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/result.csv" \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -o ./result.csv

Persistence

Within a session, a code context keeps Python state across cells. To persist the filesystem across the sandbox's life, keep work inside a live sandbox with a longer TTL, or download the workspace before cleanup.

sandbox.set_ttl(7200)
sandbox.filesystem.download("/workspace/notebook.ipynb", "./notebook.ipynb")
sandbox.kill()

Wiring this into an agent framework? See Code execution for AI agents for per-framework recipes (LangGraph, CrewAI, OpenAI Agents SDK, Vercel AI SDK, and more).

Track persistent storage work at GitHub issues.

On this page