Skip to main content
Mastra 1.0 is available 🎉 Read announcement

LocalSandbox

Executes commands on the local system.

info

For interface details, see WorkspaceSandbox Interface.

Installation
Direct link to Installation

LocalSandbox is included in @mastra/core:

npm install @mastra/core@latest

Usage
Direct link to Usage

Add a LocalSandbox to a workspace and assign it to an agent. The agent can then execute shell commands as part of its tasks:

import { Agent } from '@mastra/core/agent';
import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core/workspace';

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
sandbox: new LocalSandbox({
workingDirectory: './workspace',
env: {
NODE_ENV: 'development',
},
}),
});

const agent = new Agent({
id: 'dev-agent',
model: 'openai/gpt-4o',
workspace,
});

// The agent now has the execute_command tool available
const response = await agent.generate('Run npm install');

Auto-start behavior
Direct link to Auto-start behavior

LocalSandbox automatically starts on the first command execution if not already running. You can also explicitly start the sandbox by calling workspace.init() at application startup to avoid first-command latency.

Constructor Parameters
Direct link to Constructor Parameters

id?:

string
= Auto-generated
Unique identifier for this sandbox instance

workingDirectory?:

string
= process.cwd()/.sandbox/
Directory for command execution. Defaults to .sandbox/ in process.cwd() for isolation from seatbelt profiles.

env?:

NodeJS.ProcessEnv
Environment variables to set. PATH is included by default unless overridden.

timeout?:

number
= 30000
Default timeout for operations in milliseconds

isolation?:

'none' | 'seatbelt' | 'bwrap'
= 'none'
Native OS sandboxing backend. 'seatbelt' for macOS, 'bwrap' for Linux.

nativeSandbox?:

NativeSandboxConfig
Configuration for native sandboxing (see NativeSandboxConfig below).

NativeSandboxConfig
Direct link to NativeSandboxConfig

Configuration options for native OS sandboxing (used with isolation: 'seatbelt' or 'bwrap').

allowNetwork?:

boolean
= false
Allow network access from sandboxed commands.

readOnlyPaths?:

string[]
Additional paths to allow read-only access (system paths are always readable).

readWritePaths?:

string[]
Additional paths to allow read-write access beyond the workspace directory.

seatbeltProfilePath?:

string
Path to a custom seatbelt profile file (macOS only). If the file exists, it's used; if not, a default profile is generated and written to this path.

bwrapArgs?:

string[]
Additional arguments to pass to bwrap (Linux only).

allowSystemBinaries?:

boolean
= true
Allow read access to standard system binary paths (/bin, /usr/bin, etc.).

Properties
Direct link to Properties

id:

string
Sandbox instance identifier

name:

string
Provider name ('LocalSandbox')

provider:

string
Provider identifier ('local')

status:

ProviderStatus
'starting' | 'running' | 'stopped' | 'error'

workingDirectory:

string
The configured working directory

Methods
Direct link to Methods

start()
Direct link to start

Initialize and start the sandbox. Creates the working directory and sets up seatbelt profiles if using native isolation.

await sandbox.start();

Called automatically by workspace.init() or on first executeCommand() call.

stop()
Direct link to stop

Stop the sandbox.

await sandbox.stop();

destroy()
Direct link to destroy

Clean up sandbox resources. Removes seatbelt profiles if they were auto-generated.

await sandbox.destroy();

Called by workspace.destroy().

isReady()
Direct link to isready

Check if the sandbox is ready for operations.

const ready = await sandbox.isReady();
// true if status is 'running'

Returns: Promise<boolean>

executeCommand(command, args?, options?)
Direct link to executecommandcommand-args-options

Execute a shell command in the sandbox.

const listResult = await sandbox.executeCommand('ls', ['-la']);
const installResult = await sandbox.executeCommand('npm', ['install', 'lodash'], {
timeout: 60000,
env: { NODE_ENV: 'development' },
});

Parameters:

command:

string
Command to execute

args?:

string[]
Command arguments

options.timeout?:

number
Execution timeout in milliseconds

options.cwd?:

string
Working directory for the command

options.env?:

Record<string, string>
Additional environment variables

options.onStdout?:

(data: string) => void
Callback for stdout streaming

options.onStderr?:

(data: string) => void
Callback for stderr streaming

Returns: Promise<CommandResult>

interface CommandResult {
success: boolean;
stdout: string;
stderr: string;
exitCode: number;
executionTimeMs: number;
}

getInfo()
Direct link to getinfo

Get sandbox status and resource information.

const info = await sandbox.getInfo();
// { status: 'running', resources: { ... } }

Returns: Promise<SandboxInfo>

interface SandboxInfo {
status: 'starting' | 'running' | 'stopped' | 'error';
resources?: {
memoryMB?: number;
memoryUsedMB?: number;
cpuCores?: number;
cpuPercent?: number;
diskMB?: number;
diskUsedMB?: number;
};
}

getInstructions()
Direct link to getinstructions

Returns a description of how this sandbox works. Used in tool descriptions.

const instructions = sandbox.getInstructions();
// 'Local command execution. Working directory: "/workspace".'

Returns: string

Path Resolution
Direct link to Path Resolution

Relative paths and execution context
Direct link to Relative paths and execution context

When you use a relative path for workingDirectory, it resolves from process.cwd(). In Mastra projects, cwd varies depending on how you run your code:

ContextWorking directory./workspace resolves to
mastra dev./src/mastra/public/./src/mastra/public/workspace
mastra start./.mastra/output/./.mastra/output/workspace
Direct scriptWhere you ran the commandRelative to that location

This can cause confusion when the same relative path resolves to different locations.

For consistent paths across all execution contexts, use an environment variable with an absolute path:

import { LocalSandbox } from '@mastra/core/workspace';

const sandbox = new LocalSandbox({
workingDirectory: process.env.WORKSPACE_PATH!,
});

Set WORKSPACE_PATH in your environment to an absolute path like /home/user/my-project/workspace. This ensures commands run from a consistent directory regardless of how you run your code.

Static Methods
Direct link to Static Methods

detectIsolation()
Direct link to detectisolation

Detect the best available isolation backend for the current platform.

const detection = LocalSandbox.detectIsolation();
// { backend: 'seatbelt', available: true, message: 'Seatbelt available on macOS' }

Returns: SandboxDetectionResult

interface SandboxDetectionResult {
backend: IsolationBackend;
available: boolean;
message: string;
}

Environment Isolation
Direct link to Environment Isolation

By default, LocalSandbox only includes PATH in the environment. This allows commands to run while preventing accidental exposure of API keys and secrets.

// Default: only PATH is available (commands work, secrets protected)
const secureSandbox = new LocalSandbox({
workingDirectory: './workspace',
});

// Explicit: pass specific variables
const sandbox = new LocalSandbox({
workingDirectory: './workspace',
env: {
NODE_ENV: 'development',
API_URL: 'https://api.example.com',
},
});

// Full access (use with caution)
const devSandbox = new LocalSandbox({
workingDirectory: './workspace',
env: process.env,
});

Native OS Sandboxing
Direct link to Native OS Sandboxing

LocalSandbox supports native OS-level sandboxing for additional security:

  • macOS: Uses Seatbelt (sandbox-exec) for filesystem and network isolation
  • Linux: Uses Bubblewrap (bwrap) for namespace isolation
// Detect the best available backend for this platform
const detection = LocalSandbox.detectIsolation();
console.log(detection);
// { backend: 'seatbelt', available: true, message: '...' }

// Enable native sandboxing
const sandbox = new LocalSandbox({
workingDirectory: './workspace',
isolation: 'seatbelt', // or 'bwrap' on Linux
nativeSandbox: {
allowNetwork: false, // Block network access (default)
readWritePaths: ['/tmp/extra'], // Additional writable paths
},
});

When isolation is enabled:

  • File writes are restricted to the workspace directory (and configured paths)
  • File reads are allowed everywhere (needed for system binaries)
  • Network access is blocked by default
  • Process isolation prevents affecting the host system

Sandbox profile location
Direct link to Sandbox profile location

When using seatbelt isolation on macOS, LocalSandbox generates a profile file in a .sandbox-profiles/ folder in process.cwd(), separate from the working directory:

project/
├── .sandbox/ # Default working directory (sandboxed)
│ └── ... files created by sandbox
├── .sandbox-profiles/ # Seatbelt profiles (outside sandbox)
│ └── seatbelt-a1b2c3d4.sb # Hash based on workspace + config
└── ... your project files

The profile filename is a hash of the workspace path and configuration, so sandboxes with identical settings share the same profile while different configurations get separate files. This prevents collisions when running multiple sandboxes concurrently.

This separation prevents sandboxed processes from reading or modifying their own security profiles. The profile is created when the sandbox starts and cleaned up when destroyed.