Skip to main content
Mastra is a TypeScript framework for building agents with tools, workflows, and memory. Back an agent’s tools with sandbox.commands.run and sandbox.files so every command the model runs, and every file it writes, stays in an isolated VM instead of on your server. The model API key stays in your app; the sandbox never sees it.

Setup

The examples use Anthropic through Mastra’s model router, which reads the provider key from the environment. Any supported provider works: set OPENAI_API_KEY and pass "openai/gpt-5.5" as the model. See Models in the Mastra docs for the full list, and API keys to create a Superserve API key.

Wire the sandbox into the agent

The highlighted block defines a bash tool backed by the sandbox. Everything else is standard Mastra usage. The agent loops for up to 5 steps by default, so the model can run commands, read the results, and answer.
The tool returns stdout, stderr, and exitCode as an object, so the model sees failed commands as well as their output.

Run code with file tools

Add file tools next to bash to let the model write a script, run it, and read the result. Pass maxSteps to generate to allow longer loops.
Output from a run with claude-haiku-4-5 (trimmed; the model’s wording varies):
The tool name in payload.toolName is the key in the agent’s tools object, not the tool id. sandbox.files paths must be absolute. See Read & write files for binary content and directory downloads.

Stream tool calls

agent.stream() takes the same arguments as generate(). Read fullStream to show each tool call and its result while the agent works.
See Streaming to stream a single command’s output.

One sandbox per conversation

The examples above close over one sandbox. To serve many conversations with one agent, pass the sandbox ID to the tools through request context. Store sandbox.id with the conversation, reconnect on each turn, and pause between turns so files and installed packages stay available without paying for an idle VM.
Put only the ID in request context, not the Sandbox object. Mastra serializes request context, for example into traces and stored workflow snapshots, and a Sandbox object holds your API key and a sandbox access token. The connected Sandbox objects stay in a map in your process. Each turn pauses the sandbox when it ends, so runTurn rejects a second turn for a conversation while one is running. The map works in one process. If several servers handle the same conversation, use a shared lock or a queue per conversation. requestContextSchema types requestContext.get("sandboxId") and checks the value before the tool runs. If a call has no sandbox ID in its context, the tool returns a validation error to the model instead of running. Sandbox.connect() resumes a paused sandbox, or one that is still pausing, before it returns. See Lifecycle and Connect. The second turn finds the file because it lives in the sandbox, not because the agent remembers the first turn. To keep the chat history too, add Mastra memory to the agent.

Good to know

  • The model can call only the tools you define. Keep kill(), pause(), and update() in your application code, not in a tool.
  • To limit what model-written code can reach, create the sandbox with network rules.
  • Pass timeoutMs to commands.run. Without it, the SDK request times out after 30 seconds, so the tool call fails on longer commands such as package installs.
  • The default sandbox has python3 but no python. Tell the model in instructions, or use a template with the tools you need.
  • As a backstop for crashes, set timeoutSeconds and autoDeleteSeconds when you create the sandbox. See Auto-delete.

Resources

Mastra docs

Agents, tools, memory, and workflows in Mastra.

Run commands

Options for commands.run, including environment variables and working directory.