# LocalSandbox Executes commands on the local system. For interface details, see [WorkspaceSandbox Interface](https://mastra.ai/reference/workspace/sandbox/llms.txt). ## Installation `LocalSandbox` is included in `@mastra/core`: ```bash npm install @mastra/core@latest ``` ```bash pnpm add @mastra/core@latest ``` ```bash yarn add @mastra/core@latest ``` ```bash bun add @mastra/core@latest ``` ## 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: ```typescript 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 `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 ### id?: string Unique identifier for this sandbox instance ### workingDirectory?: string 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 Default timeout for operations in milliseconds ### isolation?: 'none' | 'seatbelt' | 'bwrap' Native OS sandboxing backend. 'seatbelt' for macOS, 'bwrap' for Linux. ### nativeSandbox?: NativeSandboxConfig Configuration for native sandboxing (see NativeSandboxConfig below). ## NativeSandboxConfig Configuration options for native OS sandboxing (used with `isolation: 'seatbelt'` or `'bwrap'`). ### allowNetwork?: boolean 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 Allow read access to standard system binary paths (/bin, /usr/bin, etc.). ## 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 ### `start()` Initialize and start the sandbox. Creates the working directory and sets up seatbelt profiles if using native isolation. ```typescript await sandbox.start(); ``` Called automatically by `workspace.init()` or on first `executeCommand()` call. ### `stop()` Stop the sandbox. ```typescript await sandbox.stop(); ``` ### `destroy()` Clean up sandbox resources. Removes seatbelt profiles if they were auto-generated. ```typescript await sandbox.destroy(); ``` Called by `workspace.destroy()`. ### `isReady()` Check if the sandbox is ready for operations. ```typescript const ready = await sandbox.isReady(); // true if status is 'running' ``` **Returns:** `Promise` ### `executeCommand(command, args?, options?)` Execute a shell command in the sandbox. ```typescript 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\ Additional environment variables ### options.onStdout?: (data: string) => void Callback for stdout streaming ### options.onStderr?: (data: string) => void Callback for stderr streaming **Returns:** `Promise` ```typescript interface CommandResult { success: boolean; stdout: string; stderr: string; exitCode: number; executionTimeMs: number; } ``` ### `getInfo()` Get sandbox status and resource information. ```typescript const info = await sandbox.getInfo(); // { status: 'running', resources: { ... } } ``` **Returns:** `Promise` ```typescript interface SandboxInfo { status: 'starting' | 'running' | 'stopped' | 'error'; resources?: { memoryMB?: number; memoryUsedMB?: number; cpuCores?: number; cpuPercent?: number; diskMB?: number; diskUsedMB?: number; }; } ``` ### `getInstructions()` Returns a description of how this sandbox works. Used in tool descriptions. ```typescript const instructions = sandbox.getInstructions(); // 'Local command execution. Working directory: "/workspace".' ``` **Returns:** `string` ## Path Resolution ### 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: | Context | Working directory | `./workspace` resolves to | | -------------- | ------------------------- | ------------------------------- | | `mastra dev` | `./src/mastra/public/` | `./src/mastra/public/workspace` | | `mastra start` | `./.mastra/output/` | `./.mastra/output/workspace` | | Direct script | Where you ran the command | Relative to that location | This can cause confusion when the same relative path resolves to different locations. ### Recommended: Use absolute paths For consistent paths across all execution contexts, use an environment variable with an absolute path: ```typescript 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 ### `detectIsolation()` Detect the best available isolation backend for the current platform. ```typescript const detection = LocalSandbox.detectIsolation(); // { backend: 'seatbelt', available: true, message: 'Seatbelt available on macOS' } ``` **Returns:** `SandboxDetectionResult` ```typescript interface SandboxDetectionResult { backend: IsolationBackend; available: boolean; message: string; } ``` ## 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. ```typescript // 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 `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 ```typescript // 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 When using seatbelt isolation on macOS, `LocalSandbox` generates a profile file in a `.sandbox-profiles/` folder in `process.cwd()`, separate from the working directory: ```text 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. ## Related - [WorkspaceSandbox Interface](https://mastra.ai/reference/workspace/sandbox/llms.txt) - [Workspace Class](https://mastra.ai/reference/workspace/workspace-class/llms.txt) - [Workspace Overview](https://mastra.ai/docs/workspace/overview/llms.txt)