Skip to content

About

A Python data analyst agent that runs its code in Render Sandboxes

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

sandbox-data-analyst

A Python template for an AI data analyst. Upload a CSV to an HTTP API and ask questions about it in plain English. Claude writes and runs Python against your data in an isolated Render Sandbox, and streams back its answer, the code it ran, and any charts it made.

Deploy to Render

$ curl -N -H "Authorization: Bearer $API_TOKEN" -H 'content-type: application/json' \
    -d '{"message": "Which region had the highest revenue? Plot the monthly trend."}' \
    $API_URL/api/sessions/$SESSION/messages

event: code
data: {"code": "import pandas as pd\ndf = pd.read_csv('/workspace/data/sales.csv') ..."}

event: result
data: {"exit_code": 0, "output": "exit code: 0\nstdout:\nregion\nSouth    144772.35 ..."}

event: file
data: {"name": "monthly_revenue_by_region.png", "url": "/api/sessions/.../files/monthly_revenue_by_region.png"}

event: text
data: {"text": "**South** had the highest total revenue at **$144,772**, narrowly ahead of East ..."}

event: done
data: {}

Why it matters

Most product agents eventually need to run code: to analyze data, transform files, or check their own answers. The code is written by a model, so it's untrusted, and it can't run in the process that holds your API keys.

This template shows the standard way to build that on Render. Your agent loop runs in an ordinary Python web service, which holds every credential. Each time the model wants to run code, the service sends that code to a Sandbox that holds no credentials and can't reach the internet. The agent gets a real Linux machine with pandas and matplotlib. Your infrastructure gets a hard boundary around everything the model writes.

It's deliberately small: one web service, under 600 lines of Python, and no framework beyond FastAPI and the Anthropic and Render SDKs. Read it in one sitting, then change the prompt, tools, and packages to build your own agent.

What it demonstrates on Render

  • Sandboxes as a tool: the agent loop runs outside the sandbox and calls it through the Render SDK, so model and Render keys never enter it.
  • One sandbox per session: each chat session gets its own sandbox. The sandbox suspends when idle between questions and wakes on the next command, so files and installed packages persist across turns.
  • Egress allow-lists: the sandbox can reach only the Python package index, which it needs to install pandas, numpy, and matplotlib at startup.
  • Web services: a FastAPI service streams each answer over server-sent events (SSE).
  • Blueprints: one render.yaml creates the service, generates its API token, and prompts for each secret.

How a question flows

  1. POST /api/sessions creates a session. The service starts creating its sandbox in the background: it creates a Python virtual environment and installs the data packages (about 15 seconds).
  2. POST /api/sessions/{id}/files uploads a CSV. The service copies it into the sandbox at /workspace/data/.
  3. POST /api/sessions/{id}/messages sends a question. The service calls Claude with the conversation so far and one tool, run_python.
  4. Each run_python call runs as a fresh Python process in the sandbox, with a 120-second timeout. Its exit code, stdout, and stderr go back to Claude, which reads them and decides what to do next.
  5. After each run, the service downloads any new files in /workspace/output/ and streams their URLs.
  6. When Claude stops calling tools, the service streams done. The sandbox suspends after five minutes idle, and the session is closed after 30 minutes idle.

Security

  • The sandbox holds no credentials. RENDER_API_KEY and ANTHROPIC_API_KEY exist only in the web service.
  • The sandbox can reach only pypi.org and files.pythonhosted.org. Everything else is blocked, so code can't send your data anywhere except, in principle, through requests to those two hosts. To remove even that, see Prebuild the environment.
  • Each session has its own sandbox, and sessions are unguessable random IDs. Anyone with API_TOKEN can create sessions and spend model tokens, so treat it like a password.
  • The service caps concurrent sessions (MAX_SESSIONS, default 10), upload size (50 MB), downloaded file size (10 MB), and tool rounds per question (20).
  • Uploaded data is sent to Anthropic as part of the conversation whenever the model prints it.

Trust boundaries covers these properties and their limits.

Get running

You need a Render workspace with Sandboxes enabled, a Render API key, your workspace ID, and an Anthropic API key.

  1. Click Deploy to Render, or create a Blueprint from your fork. Paste the three secrets it asks for.

  2. Copy the service URL and the generated API_TOKEN from the service's Environment page.

  3. Ask a question about the bundled sample data:

    export API_URL=https://<your-service>.onrender.com API_TOKEN=...
    SESSION=$(curl -s -X POST -H "Authorization: Bearer $API_TOKEN" $API_URL/api/sessions | jq -r .id)
    curl -s -H "Authorization: Bearer $API_TOKEN" -F file=@examples/sales.csv $API_URL/api/sessions/$SESSION/files
    curl -N -H "Authorization: Bearer $API_TOKEN" -H 'content-type: application/json' \
      -d '{"message": "Which product drives the most revenue? Plot it."}' \
      $API_URL/api/sessions/$SESSION/messages

To run it on your machine instead, see Run it locally. Local runs still create real sandboxes.

Learn more

License

MIT. See LICENSE.

About

A Python data analyst agent that runs its code in Render Sandboxes

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages