How to give a Mastra agent a code sandbox
Mastra agents take AI SDK tools as they are, so runtimeTools(sbx) from withruntime/ai gives one a Linux microVM to work in.
On Runtime the integration is one line in the agent's constructor, and the
machine costs $0.03125 an hour for 2 vCPU and 4 GiB while the agent waits on
its model. runtimeTools(sbx) returns four tools, to run a command and to
read, write and list files, bound to one Firecracker microVM with its own Linux
kernel. @mastra/core 1.71.0 was the current npm release on 25 September 2026;
the tools ran in a Mastra agent's own loop with Mastra 1.69.0 on
23 September 2026.
Install
Terminalnpm install withruntime @mastra/core ainpx withruntime loginwithruntime/ai needs the ai package, version 5 or later. The login prints a
link to approve in your browser; a deployed app reads RUNTIME_API_KEY.
An agent with a sandbox
TypeScriptimport { Agent, type ToolsInput } from "@mastra/core/agent";import { Sandbox } from "withruntime";import { runtimeTools } from "withruntime/ai";const sbx = await Sandbox.create({ timeoutSeconds: 900, onLeaseEnd: "stop" });try { const coder = new Agent({ id: "coder", name: "Coder", instructions: "Solve tasks by writing and running code in the sandbox. Check exit codes.", model: "anthropic/claude-sonnet-4-6", tools: runtimeTools(sbx) as unknown as ToolsInput, }); const response = await coder.generate( "Write a Node script that lists the 10 largest files in /usr and run it.", { maxSteps: 15, }, ); console.log(response.text);} finally { await sbx.stop();}The tools go to Mastra as they are. The cast is for TypeScript alone: with
ai 7 and @mastra/core 1.71.0 (25 September 2026), the AI SDK's tool type
allows things Mastra's tools type does not, although these tools use none of
them. In plain JavaScript on Node.js 24, drop the type ToolsInput import and
the cast. await using sbx = await Sandbox.create() can replace the
try/finally. maxSteps bounds how many model calls one generate makes.
The four tools the model sees are runtime_exec (with command, cwd and
timeoutSeconds), runtime_read_file, runtime_write_file and
runtime_list_files. Relative paths are under /workspace, and each output is
cut to 20,000 characters, keeping the end
(frameworks).
Mastra's own sandboxes, compared
Mastra also has workspaces, which attach a sandbox to an agent through
workspace: new Workspace({ sandbox }). From Mastra's docs, read on
25 September 2026:
| Option | Where commands run | What Mastra's docs say |
|---|---|---|
LocalSandbox, isolation: "none" |
The app's own host | The default; "isn't isolated or secure" |
LocalSandbox, "bwrap" or "seatbelt" |
The host, in Bubblewrap or Seatbelt | Writes limited to the workspace; reads allowed system-wide; network off by default |
| Remote sandbox providers | The provider's machines | Daytona, E2B, Modal, Vercel, Docker and others are listed |
runtimeTools(sbx) |
A Runtime microVM your code created | Ordinary tools on the agent; no workspace needed |
Native isolation still runs on your host's kernel and lets the code read the host's files. A Runtime sandbox holds nothing of the host: the model's code sees only what you write into it.
Per-user sandboxes
A Mastra app often serves many users. Give each user a named sandbox so their files survive between requests, and let it pause when they go quiet:
TypeScriptimport { Sandbox } from "withruntime";import { runtimeTools } from "withruntime/ai";export async function toolsFor(userId: string) { const sbx = await Sandbox.getOrCreate(`user-${userId}`, { idlePauseSeconds: 600, maxCostMicros: 50_000, }); return runtimeTools(sbx, { timeoutSeconds: 120 });}Sandbox.getOrCreate returns the same sandbox for the same name, woken if it
was paused (sandboxes by name). After ten
idle minutes it pauses with files, memory and processes kept, and compute
billing stops. Build the agent with tools: await toolsFor(userId) in the
request handler.
What else your code can do with the sandbox
- Previews.
sbx.previews.create(3000)shares an app the agent started at a private HTTPS address underruntimehost.com(share a port). - Forks.
sbx.fork({ count: 2 })makes two running copies with memory included, for a workflow step that tries two approaches at once. - Images. Build a custom image with your toolchain and create sandboxes from it, so the agent's first command does not wait on an install.
- Docker.
sudo enable-dockerinside the sandbox runs containers the agent builds (run Docker in a sandbox).
Keep keys and spending safe
- The model key stays with Mastra in your server process; the sandbox gets only commands and file contents.
maxCostMicrosat create refuses a sandbox whose first lease would cost more than that many microdollars.- A daily spending limit on the Runtime key bounds all users' sandboxes
together: a create or wake past it fails with
spending_limit_reached, and nothing is charged (read-only keys and daily limits). - A read-only key for an admin dashboard sees every sandbox and its cost and can change nothing.
- Network rules at create, such as
network: { internet: true, allow: ["registry.npmjs.org"] }, bind root in the sandbox because the host enforces them. - Secrets for services the agent's code calls: the sandbox holds a placeholder, and the host adds the value on HTTPS requests to the hosts you name (secrets).
What it costs
CPU is billed as used, $0.025 per vCPU-hour with a floor of 50 millicores, and reserved memory at $0.0075 per GiB-hour. With both CPUs busy, 2 vCPU and 4 GiB is $0.08 an hour, and a paused user sandbox pays only storage (pricing). New accounts get 50 free sandbox hours, no card.
The same tools in the AI SDK directly are in Vercel AI SDK, and per-user machines at scale are in per-user dev environments.
Sources
Checked 25 September 2026.
- Mastra sandboxes: workspaces, the
provider list and the
LocalSandboxwarning - Mastra LocalSandbox reference:
the
isolationlevels and their limits - Mastra Agent.generate:
maxStepsandresponse.text - Mastra Anthropic models: the
anthropic/claude-sonnet-4-6id - @mastra/core on npm: version
1.71.0, which exports
@mastra/core/agent
Facts on this page were checked on 25 September 2026.