Skip to main content
An agent that answers questions about data needs to write Python, look at the result, and keep going. The usual way to give it that is a code interpreter: a python tool backed by a long-running Jupyter kernel, so a dataframe loaded in one call is still in memory for the next, just like cells in a notebook. In this guide you build one on Archil and use it to analyze a year of Ookla’s open speed test data. Archil handles the three parts that are usually awkward:
  • The data stays where it is. The public S3 bucket is attached as an Archil disk and mounted read-only, so the kernel reads the Parquet files directly. There’s no download step, and pandas fetches only the columns it asks for.
  • The kernel’s memory survives between sessions. The kernel runs in a persistent sandbox. When you pause the sandbox, the kernel is frozen with it, and the next session finds the dataframes still loaded.
  • Results outlive the sandbox. The agent writes charts and reports to a second Archil disk, which your app can read without going through the sandbox.

Prerequisites

Export your Archil API key, a region where sandboxes are available (aws-us-east-1, aws-us-west-2, or aws-eu-west-1), and an AI Gateway key for the model. The Ookla bucket is in us-west-2, so that region is the closest to the data.
Then install the dependencies. The TypeScript agent uses the AI SDK; the Python agent calls the same model through the gateway’s OpenAI-compatible API.

Run a kernel in the sandbox

Two files run inside the sandbox. The first is a setup script that installs pandas and Jupyter’s ipykernel into a virtual environment and starts a kernel as a supervised service named kernel. The kernel’s connection file, which holds its ports and signing key, is written in advance to /root/kernel.json, so clients can find the kernel and it keeps the same address if the service restarts. MPLBACKEND=Agg makes matplotlib render to files instead of trying to display plots.
setup.sh
The second is a small client that runs one piece of code in that kernel, the same way a notebook runs a cell. It reads the code from the CODE environment variable, prints whatever the code prints, the value of its last expression, and any traceback, and exits. The kernel keeps running, so the next call sees the same variables. If code runs for more than 100 seconds, the client interrupts it, like pressing stop in a notebook, and the kernel’s state is kept.
run.py
The kernel has no network port, so nothing outside the sandbox can reach it. Your code talks to it only through sandbox.exec.

Define the agent

The agent has one tool, python, that runs run.py with sandbox.exec. The instructions describe the dataset, so the agent doesn’t spend steps discovering it, and tell it to load data once and reuse it.
Passing the code in an environment variable hands it to the kernel exactly as the model wrote it, with no shell quoting. runPython is exported so your own code can use the kernel too, which the second session does.

Run the first analysis

The first session creates two disks. ookla-speedtests is backed by the public ookla-open-data bucket, so it needs no credentials, and it’s mounted at /data. analysis-workspace is an empty disk for results, mounted at /workspace. The script then creates the sandbox, runs setup.sh, and asks the agent a question that takes several steps to answer.
A disk backed by a public bucket is read-only: Archil has no credentials to write to someone else’s bucket. Always mount it with readOnly: true (read_only=True in Python), and send everything the agent writes to a separate disk.
When the agent finishes, archil sync flushes the kernel’s writes to the disk, and the script reads the chart and the report straight from analysis-workspace with getObject. Finally, it pauses the sandbox, which stops compute and snapshots memory, including the kernel.
The agent prints each piece of code it runs, followed by the output. Its first call loads the four quarters, about 26 million rows, into tiles, and every call after that works on the dataframe already in memory. Output from one run, trimmed:
The chart, downloaded from the disk to download-by-quarter.png: Line chart of test-weighted mean fixed broadband download speed by quarter in 2024, rising from 169 to 196 Mbps worldwide and from 269 to 303 Mbps in the contiguous US

Continue in a later session

A paused sandbox keeps its memory, so the kernel and everything in it come back on resume(). Before handing the agent its next question, the script runs a line of its own in the kernel to show that tiles is still loaded. The agent then builds on it without reading the files again.
The first line comes from the script’s own runPython call, before the agent does anything. After that, the agent checks what’s in the kernel and answers from tiles without reading any Parquet files. Output from one run, trimmed:
Pausing is the right default between sessions that are minutes or hours apart. If you stop() the sandbox instead, memory is discarded: the kernel service starts again on the next boot with an empty kernel, and the agent reloads the data. The Python environment on the root filesystem and everything in /workspace are kept either way.

Clean up

A sandbox must be stopped before it can be deleted, and a paused sandbox can be stopped directly. Stop and delete the sandbox, then delete both disks. Deleting ookla-speedtests removes only the Archil disk, not the public bucket behind it.

Next steps

Coding agent

Give an agent a bash tool and a persistent sandbox to build and run a web app.

Persistent sandboxes

Lifecycle, services, pausing, and network access in detail.

Sharing disks

Mount one disk in several sandboxes at once with read-only and conditional mounts.

Python SDK

Full reference for sandboxes, disks, and exec options.