# LocalSandbox

**Added in:** `@mastra/core@1.1.0`

Executes commands on the local system.

> **Info:** For interface details, see [WorkspaceSandbox interface](https://mastra.ai/reference/workspace/sandbox).

## 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-5.4',
  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 (Default: `Auto-generated`)

**workingDirectory** (`string`): Directory for command execution. Defaults to .sandbox/ in process.cwd() for isolation from seatbelt profiles. (Default: `process.cwd()/.sandbox/`)

**env** (`NodeJS.ProcessEnv`): Environment variables to set. PATH is included by default unless overridden.

**timeout** (`number`): Default timeout for operations in milliseconds (Default: `30000`)

**isolation** (`'none' | 'seatbelt' | 'bwrap'`): Native OS sandboxing backend. 'seatbelt' for macOS, 'bwrap' for Linux. (Default: `'none'`)

**instructions** (`string | ((opts: { defaultInstructions: string; requestContext?: RequestContext }) => string)`): Custom instructions that override the default instructions returned by getInstructions(). Pass a string to fully replace them, or a function to extend them with access to the current requestContext for per-request customization.

**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. (Default: `false`)

**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.). (Default: `true`)

## 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

**processes** (`LocalProcessManager`): Background process manager. See \[SandboxProcessManager reference]\(/reference/workspace/process-manager).

## 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.

## Background processes

`LocalSandbox` includes a built-in process manager for spawning and managing background processes. Processes run as child processes on the local machine using `child_process.spawn`.

```typescript
const sandbox = new LocalSandbox({ workingDirectory: './workspace' })
await sandbox.start()

// Spawn a background process
const handle = await sandbox.processes.spawn('node server.js')

// Read output, send stdin, kill
console.log(handle.stdout)
await handle.sendStdin('input\n')
await handle.kill()
```

When native isolation is enabled (`seatbelt` or `bwrap`), spawned processes are also wrapped with the same isolation backend.

See [`SandboxProcessManager` reference](https://mastra.ai/reference/workspace/process-manager) for the full API.

## 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' }
```

## 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

- [SandboxProcessManager reference](https://mastra.ai/reference/workspace/process-manager)
- [WorkspaceSandbox Interface](https://mastra.ai/reference/workspace/sandbox)
- [Workspace Class](https://mastra.ai/reference/workspace/workspace-class)
- [Workspace Overview](https://mastra.ai/docs/workspace/overview)