PandaStack

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
"
sandbox.kill()

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
"

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)

For larger files, use upload and download helpers:

sandbox.filesystem.upload("./data.csv", "/workspace/data.csv")
sandbox.filesystem.download("/workspace/result.csv", "./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