# Workspaces

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

A Mastra workspace gives agents a persistent environment for storing files and executing commands. Agents use workspace tools to read and write files, run shell commands, and search indexed content.

A workspace supports the following features:

- **[Filesystem](https://mastra.ai/docs/workspace/filesystem)**: File storage (read, write, list, delete, copy, move, grep)
- **[Sandbox](https://mastra.ai/docs/workspace/sandbox)**: Command execution (shell commands) and background processes
- **[LSP inspection](https://mastra.ai/docs/workspace/lsp)**: Hover, definition, and implementation queries through language servers
- **[Search](https://mastra.ai/docs/workspace/search)**: BM25, vector, or hybrid search over indexed content
- **[Skills](https://mastra.ai/docs/workspace/skills)**: Reusable instructions for agents

## When to use workspaces

Use a workspace when your agent needs access to the local filesystem, shell commands, semantic code inspection, indexed search, or reusable skill instructions.

## How it works

When you assign a workspace to an agent, Mastra includes the corresponding tools in the agent's toolset. The agent can then use these tools to interact with files and execute commands.

You can create a workspace with any combination of the supported features. The agent receives only the tools relevant to what's configured.

## Usage

### Creating a workspace

Create a workspace by instantiating the `Workspace` class with your desired features:

```typescript
import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core/workspace'

const workspace = new Workspace({
  filesystem: new LocalFilesystem({
    basePath: './workspace',
  }),
  sandbox: new LocalSandbox({
    workingDirectory: './workspace',
  }),
  skills: ['/skills'],
})
```

The `skills` array specifies paths to directories containing skill definitions, see [Skills](https://mastra.ai/docs/workspace/skills).

### Global workspace

Set a workspace on the Mastra instance. All agents inherit this workspace unless they define their own:

```typescript
import { Mastra } from '@mastra/core'
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'

const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './workspace' }),
})

const mastra = new Mastra({
  workspace,
})
```

### Agent-level workspace

Assign a workspace directly to an agent to override the global workspace:

```typescript
import { Agent } from '@mastra/core/agent'
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'

const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './agent-workspace' }),
})

export const myAgent = new Agent({
  id: 'my-agent',
  model: 'openai/gpt-5.4',
  workspace,
})
```

## Configuration patterns

Workspaces support several configuration patterns depending on what capabilities your agent needs. The two main building blocks are `filesystem` (file tools) and `sandbox` (command execution), with `mounts` as the way to bridge cloud storage into sandboxes.

### Filesystem + sandbox (local)

For local development, pair a `LocalFilesystem` and `LocalSandbox` pointed at the same directory. Since both operate on the local machine, files written through the filesystem are immediately available to commands in the sandbox:

```typescript
const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './workspace' }),
  sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
})
```

The agent receives both file tools and `execute_command`. This is the simplest full-featured setup.

### Mounts + sandbox (cloud storage)

When you need cloud storage accessible inside a sandbox, use `mounts`. This FUSE-mounts the cloud filesystem into the sandbox so commands can read and write files at the mount path:

```typescript
const workspace = new Workspace({
  mounts: {
    '/data': new S3Filesystem({
      bucket: 'my-bucket',
      region: 'us-east-1',
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    }),
    '/skills': new GCSFilesystem({
      bucket: 'agent-skills',
    }),
  },
  sandbox: new E2BSandbox({ id: 'dev-sandbox' }),
})
```

Under the hood, `mounts` creates a [CompositeFilesystem](https://mastra.ai/docs/workspace/filesystem) that routes file tool operations to the correct provider based on path prefix. Commands in the sandbox access the mounted paths directly (e.g., `ls /data`).

You can mount multiple providers at different paths. Each mount path must be unique and non-overlapping.

> **Note:** `filesystem` and `mounts` are mutually exclusive — you can't use both in the same workspace. Use `filesystem` for a single provider without a sandbox, or `mounts` when you need to combine cloud storage with a sandbox.

### Filesystem only

Use a single `filesystem` when agents only need to read and write files. No command execution is available.

```typescript
const workspace = new Workspace({
  filesystem: new S3Filesystem({
    bucket: 'my-bucket',
    region: 'us-east-1',
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  }),
})
```

The agent receives file tools (`read_file`, `write_file`, `list_directory`, `grep`, etc.) that operate directly against the storage provider.

### Sandbox only

Use a single `sandbox` when agents only need to execute commands. No file tools are added.

```typescript
const workspace = new Workspace({
  sandbox: new E2BSandbox({ id: 'dev-sandbox' }),
})
```

The agent receives the `execute_command` tool.

### Which pattern should I use?

| Scenario                                              | Pattern                                               |
| ----------------------------------------------------- | ----------------------------------------------------- |
| Local development with files and commands             | `filesystem` + `sandbox` (both local, same directory) |
| Cloud storage accessible inside a cloud sandbox       | `mounts` + `sandbox`                                  |
| Multiple cloud providers in one sandbox               | `mounts` + `sandbox` (one mount per provider)         |
| Agent reads/writes files, no command execution needed | `filesystem` only                                     |
| Agent runs commands, no file tools needed             | `sandbox` only                                        |

## Tool configuration

Configure tool behavior through the `tools` option on the workspace. This controls which tools are enabled and how they behave.

```typescript
import { Workspace, LocalFilesystem, LocalSandbox, WORKSPACE_TOOLS } from '@mastra/core/workspace'

const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './workspace' }),
  sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
  tools: {
    // Global defaults
    enabled: true,
    requireApproval: false,

    // Per-tool overrides
    [WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]: {
      requireApproval: true,
      requireReadBeforeWrite: true,
    },
    [WORKSPACE_TOOLS.FILESYSTEM.DELETE]: {
      enabled: false,
    },
    [WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: {
      requireApproval: true,
    },
  },
})
```

### Tool options

| Option                   | Type                              | Description                                                                                                                                      |
| ------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled`                | `boolean \| (context) => boolean` | Whether the tool is available (default: `true`). When a function, evaluated at tool-listing time.                                                |
| `requireApproval`        | `boolean \| (context) => boolean` | Whether the tool requires user approval before execution (default: `false`). When a function, evaluated at execution time with access to `args`. |
| `requireReadBeforeWrite` | `boolean \| (context) => boolean` | For write tools: require reading the file first (default: `false`). When a function, evaluated at execution time with access to `args`.          |
| `name`                   | `string`                          | Custom name for the tool. Replaces the default `mastra_workspace_*` name.                                                                        |
| `maxOutputTokens`        | `number`                          | Maximum tokens for tool output (default: `2000`). Output exceeding this limit is truncated using tiktoken.                                       |

### Dynamic tool configuration

Tool options that accept functions receive a context object and return a boolean. This enables context-aware tool behavior.

```typescript
const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './workspace' }),
  tools: {
    // Dynamic enabled: disable command execution unless explicitly allowed
    [WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: {
      enabled: async ({ requestContext }) => {
        return requestContext['allowExecution'] === 'true'
      },
    },

    // Dynamic requireApproval: only require approval for protected paths
    [WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]: {
      requireApproval: async ({ args }) => {
        return (args.path as string).startsWith('/protected')
      },
      requireReadBeforeWrite: true,
    },
  },
})
```

Functions for `enabled` receive `{ requestContext, workspace }`. Functions for `requireApproval` and `requireReadBeforeWrite` also receive `args` since they are evaluated when the tool is called.

### Tool name remapping

Rename workspace tools to match the conventions your agent expects. The config key remains the original `WORKSPACE_TOOLS` constant — only the exposed name changes.

```typescript
import { Workspace, LocalFilesystem, LocalSandbox, WORKSPACE_TOOLS } from '@mastra/core/workspace'

const workspace = new Workspace({
  filesystem: new LocalFilesystem({ basePath: './workspace' }),
  sandbox: new LocalSandbox({ workingDirectory: './workspace' }),
  lsp: true,
  tools: {
    [WORKSPACE_TOOLS.FILESYSTEM.READ_FILE]: { name: 'view' },
    [WORKSPACE_TOOLS.FILESYSTEM.GREP]: { name: 'search_content' },
    [WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES]: { name: 'find_files' },
    [WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: { name: 'execute_command' },
    [WORKSPACE_TOOLS.LSP.LSP_INSPECT]: { name: 'lsp_inspect' },
  },
})
```

The agent sees `view`, `search_content`, `find_files`, `execute_command`, and `lsp_inspect` instead of the default `mastra_workspace_*` names. Tool names must be unique — duplicate names or conflicts with other default names throw an error.

## LSP inspection

Enable `lsp` on a workspace to add semantic code inspection through language servers. This adds the `mastra_workspace_lsp_inspect` tool by default, which can return hover information, definition locations, and implementations for a symbol at a specific cursor position.

See [LSP inspection](https://mastra.ai/docs/workspace/lsp) for configuration, examples, and tool name remapping.

### Output truncation

Workspace tools automatically truncate large outputs to avoid exceeding LLM context limits. Two layers of truncation apply:

1. **Line-based tail**: Command output is limited to the last 200 lines by default (configurable per-command via the `tail` parameter)
2. **Token-based limit**: Tool output is capped at 2000 tokens by default

Set `maxOutputTokens` per tool to adjust the token limit:

```typescript
const workspace = new Workspace({
  // ...
  tools: {
    [WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: {
      maxOutputTokens: 5000,
    },
  },
})
```

ANSI escape codes (colors, cursor sequences) are automatically stripped from command output before it reaches the model.

### Read-before-write

When `requireReadBeforeWrite` is enabled on write tools, agents must read a file before writing to it. This prevents overwriting files the agent hasn't seen:

- **New files**: Can be written without reading (they don't exist yet)
- **Existing files**: Must be read first
- **Externally modified files**: If a file changed since the agent read it, the write fails

File write safety is enforced at two layers:

1. **Tool layer**: Before a write tool runs, the read tracker checks whether the file was modified since it was last read. If it was, the tool throws a `FileReadRequiredError`.
2. **Filesystem layer**: At write time, `writeFile()` compares the file's current modification time against the expected value (passed via `expectedMtime` in write options). If they don't match, it throws a `StaleFileError`. This catches external modifications (for example, an editor saving the file) that happen between the tool-level check and the actual write.

When `requireReadBeforeWrite` is enabled, workspace tools pass the recorded modification time through automatically. You can also use `expectedMtime` directly when calling `filesystem.writeFile()` outside of tools:

```typescript
const stat = await filesystem.stat('/docs/file.md')
// ... later ...
await filesystem.writeFile('/docs/file.md', newContent, {
  expectedMtime: stat.modifiedAt,
})
```

## Initialization

Calling `init()` is optional in most cases—some providers initialize on first operation. Call `init()` manually when using a workspace outside of Mastra (standalone scripts, tests) or when you need to pre-provision resources before the first agent interaction.

```typescript
import { Workspace, LocalFilesystem, LocalSandbox } from '@mastra/core/workspace'

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

// Optional: pre-create directories and sandbox before first use
await workspace.init()
```

### What `init()` does

Initialization runs setup logic for each configured provider:

- `LocalFilesystem`: Creates the base directory if it doesn't exist
- `LocalSandbox`: Creates the working directory
- `Search` (if configured): Indexes files from `autoIndexPaths`, see [Search and Indexing](https://mastra.ai/docs/workspace/search)

External providers may perform additional setup like establishing connections or authenticating.

## Related

- [Filesystem](https://mastra.ai/docs/workspace/filesystem)
- [Sandbox](https://mastra.ai/docs/workspace/sandbox)
- [LSP inspection](https://mastra.ai/docs/workspace/lsp)
- [Skills](https://mastra.ai/docs/workspace/skills)
- [Search and indexing](https://mastra.ai/docs/workspace/search)
- [Workspace class reference](https://mastra.ai/reference/workspace/workspace-class)