UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

228 lines (168 loc) 9.61 kB
# Filesystem **Added in:** `@mastra/core@1.1.0` Filesystem providers give agents the ability to read, write, and manage files. When you configure a filesystem on a workspace, agents receive tools for file operations. A filesystem provider handles all file operations for a workspace: - **Read** - Read file contents - **Write** - Create and update files - **List** - Browse directories with optional glob pattern filtering - **Delete** - Remove files and directories - **Stat** - Get file metadata - **Copy/Move** - Copy or move files between locations - **Grep** - Search file contents using regex patterns ## Supported providers Available providers: - [`LocalFilesystem`](https://mastra.ai/reference/workspace/local-filesystem): Stores files in a directory on disk - [`S3Filesystem`](https://mastra.ai/reference/workspace/s3-filesystem): Stores files in Amazon S3 or S3-compatible storage (R2, MinIO, Tigris) - [`GCSFilesystem`](https://mastra.ai/reference/workspace/gcs-filesystem): Stores files in Google Cloud Storage - [`GoogleDriveFilesystem`](https://mastra.ai/reference/workspace/google-drive-filesystem): Stores files inside a Google Drive folder - [`AzureBlobFilesystem`](https://mastra.ai/reference/workspace/azure-blob-filesystem): Stores files in Azure Blob Storage - [`AgentFSFilesystem`](https://mastra.ai/reference/workspace/agentfs-filesystem): Stores files in a Turso/SQLite database via AgentFS > **Tip:** `LocalFilesystem` is the simplest way to get started as it requires no external services. For cloud storage, use `S3Filesystem`, `GCSFilesystem`, or `AzureBlobFilesystem`. For database-backed storage without external services, use `AgentFSFilesystem`. ## Basic usage Create a workspace with a filesystem and assign it to an agent. The agent can then read, write, and manage files as part of its tasks: ```typescript import { Agent } from '@mastra/core/agent' import { Workspace, LocalFilesystem } from '@mastra/core/workspace' const workspace = new Workspace({ filesystem: new LocalFilesystem({ basePath: './workspace', }), }) const agent = new Agent({ id: 'file-agent', model: 'openai/gpt-5.4', instructions: 'You are a helpful file management assistant.', workspace, }) // The agent now has filesystem tools available const response = await agent.generate('List all files in the workspace') ``` ## Containment By default, `LocalFilesystem` runs in **contained mode** — all file operations are restricted to stay within `basePath`. This prevents path traversal attacks and symlink escapes. In contained mode: - **Relative paths** (e.g. `src/index.ts`) resolve against `basePath` - **Absolute paths** (e.g. `/home/user/.config/file.txt`) are treated as real filesystem paths — if they fall outside `basePath` and any `allowedPaths`, a `PermissionError` is thrown - **Tilde paths** (e.g. `~/Documents`) expand to the home directory and follow the same containment rules If your agent needs to access specific paths outside `basePath`, use `allowedPaths` to grant access without disabling containment entirely. Relative paths are resolved against `basePath`, and absolute paths are used as-is: ```typescript const workspace = new Workspace({ filesystem: new LocalFilesystem({ basePath: './workspace', allowedPaths: ['~/.claude/skills', '../shared-data'], }), }) ``` Allowed paths can be updated at runtime using the `setAllowedPaths()` method: ```typescript // Add a path dynamically workspace.filesystem.setAllowedPaths(prev => [...prev, '/home/user/documents']) ``` This is the recommended approach for least-privilege access — the agent can only reach the specific directories you allow. If your agent needs unrestricted access to the entire filesystem, disable containment: ```typescript const workspace = new Workspace({ filesystem: new LocalFilesystem({ basePath: './workspace', contained: false, }), }) ``` When `contained` is `false`, absolute paths are treated as real filesystem paths with no restriction. ## Dynamic filesystem The `filesystem` option accepts a resolver function instead of a static instance. The resolver receives `requestContext` and returns a filesystem per request, allowing a single workspace to serve different filesystems based on the caller's identity, role, or tenant. ```typescript import { Agent } from '@mastra/core/agent' import { Workspace, LocalFilesystem } from '@mastra/core/workspace' const workspace = new Workspace({ filesystem: ({ requestContext }) => { const role = requestContext.get('agent-role') || 'guest' return new LocalFilesystem({ basePath: `/workspaces/${role}`, readOnly: role !== 'admin', }) }, }) const agent = new Agent({ id: 'multi-role-agent', model: 'openai/gpt-4o', workspace, }) ``` Each request resolves its own filesystem at tool execution time: ```typescript import { RequestContext } from '@mastra/core/request-context' // Admin request — reads and writes from /workspaces/admin/ const adminCtx = new RequestContext([['agent-role', 'admin']]) await agent.generate('Write report.txt with Q4 results', { requestContext: adminCtx }) // Viewer request — reads from /workspaces/viewer/, writes are blocked const viewerCtx = new RequestContext([['agent-role', 'viewer']]) await agent.generate('Read info.txt', { requestContext: viewerCtx }) ``` The resolver can also be asynchronous, for example to look up configuration from a database: ```typescript const workspace = new Workspace({ filesystem: async ({ requestContext }) => { const tenantConfig = await db.getTenant(requestContext.get('tenant-id')) return new LocalFilesystem({ basePath: tenantConfig.storagePath }) }, }) ``` > **Note:** `filesystem` and `mounts` are mutually exclusive. You cannot use a resolver function together with `mounts` in the same workspace. ## Read-only mode To prevent agents from modifying files, enable read-only mode: ```typescript const workspace = new Workspace({ filesystem: new LocalFilesystem({ basePath: './workspace', readOnly: true, }), }) ``` With a static filesystem, write tools (`write_file`, `edit_file`, `delete`, `mkdir`) are excluded from the agent's toolset entirely. The agent can still read and list files. When using a [dynamic filesystem](#dynamic-filesystem), write tools are always included because `readOnly` isn't known until the resolver runs. Instead, write operations are blocked at runtime — the tool returns an error if the resolved filesystem is read-only. ## Mounts and `CompositeFilesystem` When you use the `mounts` option on a workspace, Mastra creates a `CompositeFilesystem` that routes file operations to the correct provider based on path prefix. ```typescript import { Workspace } from '@mastra/core/workspace' import { S3Filesystem } from '@mastra/s3' import { GCSFilesystem } from '@mastra/gcs' import { E2BSandbox } from '@mastra/e2b' 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' }), }) ``` With this configuration: - `read_file('/data/input.csv')` reads from the S3 bucket - `write_file('/skills/guide.md', content)` writes to the GCS bucket - `list_directory('/')` returns virtual entries for `/data` and `/skills` - Commands in the sandbox can access files at `/data` and `/skills` via FUSE mounts ### Path routing All file paths must start with a mount prefix. Operations on paths that don't match any mount will fail. Listing the root directory (`/`) returns virtual directory entries for each mount point. Mount paths can't be nested — for example, you can't mount at both `/data` and `/data/sub`. ### `filesystem` vs `mounts` `filesystem` and `mounts` are mutually exclusive options on a workspace: - Use **`filesystem`** when you have a single storage provider and don't need to mount it into a sandbox. The agent gets file tools that operate directly against the provider. - Use **`mounts`** when you need cloud storage accessible inside a sandbox, or when you want to combine multiple providers. The workspace creates a CompositeFilesystem for file tools and FUSE-mounts the storage into the sandbox. For local development, you typically don't need `mounts` — a `LocalFilesystem` and `LocalSandbox` pointed at the same directory gives you both file tools and command execution on the same files. See [configuration patterns](https://mastra.ai/docs/workspace/overview) for more detail. ## Agent tools When you configure a filesystem on a workspace, agents receive tools for reading, writing, listing, and deleting files. See [workspace class reference](https://mastra.ai/reference/workspace/workspace-class) for details. ## Related - [LocalFilesystem reference](https://mastra.ai/reference/workspace/local-filesystem) - [S3Filesystem reference](https://mastra.ai/reference/workspace/s3-filesystem) - [GCSFilesystem reference](https://mastra.ai/reference/workspace/gcs-filesystem) - [GoogleDriveFilesystem reference](https://mastra.ai/reference/workspace/google-drive-filesystem) - [AzureBlobFilesystem reference](https://mastra.ai/reference/workspace/azure-blob-filesystem) - [AgentFSFilesystem reference](https://mastra.ai/reference/workspace/agentfs-filesystem) - [Workspace overview](https://mastra.ai/docs/workspace/overview) - [Sandbox](https://mastra.ai/docs/workspace/sandbox)