sandbox.commands.run and sandbox.files so every command the agent runs, and every file it writes, stays in an isolated VM instead of on your server. The model API key stays with the agent runtime; the sandbox never sees it.
Setup
await, so run them as ES modules: set "type": "module" in package.json and run each file with npx tsx.
The examples use Anthropic. To use OpenAI, set OPENAI_API_KEY and pass model: "openai/gpt-5.5" to createAgent. See API keys to create a Superserve API key.
Wire the sandbox into the agent
The highlighted block defines abash tool backed by the sandbox. Letta runs the tool’s execute function in your process, so the command goes to the sandbox through the Superserve SDK.
allowedToolsis the exact list of client-side tools the agent can call. Letta agents also have built-in client-side tools, such asBash,Read, andWrite, that run on the machine that hosts the agent runtime. List only your sandbox tools so the agent cannot use them.baseTools: []attaches no server-side tools to the agent. By default,createAgentasks for theweb_searchandfetch_webpagetools, which run outside the sandbox and its network rules.- Letta asks for approval before each tool call by default.
permissionMode: "unrestricted"approves every call. To decide per call, see Approve tool calls.
stdout, stderr, and exitCode, so the agent sees failed commands as well as their output.
Run code with file tools
Add file tools next tobash to let the agent write a script, run it, and read the result. Put the tools in a function that takes a sandbox, so you can reuse them:
sandbox-tools.ts
claude-sonnet-5-5 (the model’s wording varies):
sandbox.files paths must be absolute. See Read & write files for binary content and directory downloads.
Stream tool calls
client.prompt returns only the final result. Open a session and read session.stream() to show each tool call and its output while the agent works.
One sandbox per agent
A Letta agent keeps its memory across conversations, so give it a sandbox that lasts as long. Tag the sandbox with the agent ID, find it on each turn, and pause it between turns so files and installed packages stay available without paying for an idle VM.client.prompt starts a new conversation on each call. resumeSession continues the agent’s default conversation, so the second turn knows about the file from the first. Sandbox.connect() resumes a paused sandbox before it returns. It waits up to 30 seconds for a pause that is still in progress, so pause({ wait: true }) makes sure the pause is done before the next turn. See Lifecycle and Metadata.
Use a self-hosted App Server
Thelocal backend starts a Letta App Server as a child process of your app. To run one App Server for many app processes, start it yourself with the model API key in its environment:
remote backend. The tools still run in your app process, so commands still go to the sandbox:
Approve tool calls
In the file tools example, replacepermissionMode with a canUseTool callback to check each call before it reaches the sandbox. The agent reads the deny message and can change its plan.
permissionMode: "unrestricted" or canUseTool, the turn stops and waits for an approval. See Permissions in the Letta docs.
Use the Superserve MCP server
To let the agent create and manage sandboxes itself, connect the Superserve MCP server instead of defining tools. MCP tools are namedmcp__<server>__<tool>. List the ones the agent can call in allowedTools.
canUseTool callback changes each sandbox_create call before it runs: it tags the sandbox with the agent ID, pauses it after one hour of active time, and deletes it 10 minutes after it pauses. The finally block deletes every tagged sandbox that is left, even if the turn fails. See Auto-delete.
Good to know
- The agent can call only the client-side tools in
allowedToolsand the server-side tools inbaseTools. Keepkill(),pause(), andupdate()in your application code, not in a tool. - To limit what agent-written code can reach, create the sandbox with network rules.
- Pass
timeoutMstocommands.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
python3but nopython. Tell the agent in the prompt, or use a template with the tools you need. - As a backstop for crashes, set
timeoutSecondsandautoDeleteSecondswhen you create the sandbox. See Auto-delete.
Resources
Letta Agent SDK docs
Agents, sessions, tools, and permissions in the Letta Agent SDK.
Run commands
Options for
commands.run, including environment variables and working directory.