EphemeralBox gives you exactly two capabilities: code execution and file operations. That turns out to be all you need to hand an AI agent a real, disposable computer. This guide uses both. The model writes the code, and a single tool moves files in and out of the sandbox to run it against.
We’ll build a file editor with TanStack AI. The user uploads a file and asks for a change. The model writes the code to do it. A single tool then spins up a Box, uploads the file, runs that code, downloads the result, and tears the Box down. The model’s code and its dependencies never touch your server. They run inside an isolated sandbox that exists only for the length of the call.
1. Installation
.env.local
2. The API route
The route hands the model a singleeditFile tool. Each time the model calls it, the tool runs one self-contained lifecycle: it creates a fresh EphemeralBox, uploads the user’s file, runs the model’s code, finds the result with files.list, reads it back, and deletes the Box in a finally. The model writes code that reads the input file and drops its result into an output directory. Those four calls (files.write, exec, files.list, and files.read) are the entire EphemeralBox surface, and they’re enough to drive a real feature.
app/api/chat/route.ts
The file tools (
files.write, files.list, and files.read) are rooted at /workspace/home, and paths outside it are rejected. exec can write anywhere, but anything you move through the files API has to live under /workspace/home. That’s why both the input file and OUT_DIR sit there.files.list, nothing here is image-specific. Ask for “convert this CSV to JSON” and the model uses pandas to write out/data.json, and the tool reads it back the same way. To support more formats, add their libraries to the pip install line, or bake them into a snapshot.
3. The UI
Wire upuseChat from @tanstack/ai-react. The uploaded file rides along on the request through the connection’s dynamic body option. TanStack AI delivers that payload to the server under forwardedProps, which is why the route reads forwardedProps.file instead of a top-level field. We keep the file in a ref so each send picks up the latest one. Tool-call parts carry the typed output, so we render images inline and show a download link for everything else. A plain text prompt with no file is just a normal chat turn.
app/page.tsx
4. Try it
Run your Next.js app, upload a file, and describe the edit. With a color photo and “make it black and white,” the model writes a few lines of Pillow:editFile tool runs it, finds out/photo.png via files.list, reads it back as base64, and the UI renders the grayscale image under your message.
Swap the input and the prompt, and the same path carries the feature end to end:
- CSV to JSON: ask “convert this to JSON” and the model uses pandas to write
out/data.json, which the UI shows as a download link. - Uppercase the headings in a Markdown file, resize an image, or extract a page from a PDF. Anything the model can express in Python with the installed libraries works.
EphemeralBox that was created for the call and deleted the moment it returned. The whole editor is just two EphemeralBox capabilities wired into one tool: exec, plus the file operations write, list, and read.