Skip to content

Feat/dynamic filesystem resolver#13150

Draft
intojhanurag wants to merge 3 commits intomastra-ai:mainfrom
intojhanurag:feat/dynamic-filesystem-resolver
Draft

Feat/dynamic filesystem resolver#13150
intojhanurag wants to merge 3 commits intomastra-ai:mainfrom
intojhanurag:feat/dynamic-filesystem-resolver

Conversation

@intojhanurag
Copy link
Contributor

@intojhanurag intojhanurag commented Feb 17, 2026

Description

Workspace options like skills, instructions, model, tools, and memory already support dynamic functions that receive requestContext, but the filesystem only accepted a static instance.

This PR adds support for a resolver function
({ requestContext }) => WorkspaceFilesystem, allowing a single Workspace instance to serve different filesystems per request.

This enables multi-role agents to scope each role to a different filesystem root or permissions.

Key Changes

  • Added WorkspaceFilesystemResolver type and widened filesystem config to accept it
  • Added hasFilesystemConfig() and resolveFilesystem() public methods on Workspace
  • All 7 auto-injected workspace tools now resolve filesystem at execution time via getFs()
  • Runtime readOnly enforcement for dynamically resolved filesystems on write/edit/delete/mkdir tools
  • Fully backward compatible — static filesystem works exactly as before

Related Issue(s)

Fixes #13133

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test update

Checklist

  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works

Summary by CodeRabbit

  • New Features

    • Workspace now supports dynamic per-request filesystem resolution so different filesystems can be selected based on request context.
    • Workspace tooling now honors per-request filesystem selection, with context-aware routing.
  • Behavior Changes

    • Runtime enforcement of read-only constraints for dynamically resolved filesystems.
  • Tests

    • Added comprehensive tests covering dynamic filesystem resolution and access control.

… in Workspace

Signed-off-by: intojhanurag <aojharaj2004@gmail.com>
Signed-off-by: intojhanurag <aojharaj2004@gmail.com>
@changeset-bot
Copy link

changeset-bot bot commented Feb 17, 2026

🦋 Changeset detected

Latest commit: c2ecd33

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@mastra/core Minor
@mastra/mcp-docs-server Patch
@internal/playground Patch
@mastra/client-js Patch
@mastra/react Patch
@mastra/opencode Patch
@mastra/longmemeval Patch
mastra Patch
@mastra/deployer-cloud Minor
@mastra/playground-ui Patch
@mastra/server Minor
@mastra/deployer Minor
create-mastra Patch
@mastra/express Patch
@mastra/fastify Patch
@mastra/hono Patch
@mastra/koa Patch
@mastra/deployer-cloudflare Patch
@mastra/deployer-netlify Patch
@mastra/deployer-vercel Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Feb 17, 2026

@intojhanurag is attempting to deploy a commit to the Mastra Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

Walkthrough

Adds per-request dynamic filesystem resolution to Workspace via a resolver function (receiving requestContext). Workspace gains resolver plumbing and helpers; workspace tools now resolve filesystem at runtime, accept execution context, and enforce read-only constraints for resolver-based filesystems. Tests added for resolver behavior and access control.

Changes

Cohort / File(s) Summary
Changeset
​.changeset/dynamic-filesystem-resolver.md
Bumps @mastra/core and documents the new dynamic filesystem resolver option and usage scenarios.
Core Workspace Implementation
packages/core/src/workspace/workspace.ts
Adds WorkspaceFilesystemResolver export; WorkspaceConfig.filesystem now accepts a resolver or static filesystem. Introduces _filesystemResolver, hasFilesystemConfig(), and resolveFilesystem({ requestContext }). Adjusts constructor/validation and logger propagation for resolver-based config.
Workspace Tools Implementation
packages/core/src/workspace/tools/tools.ts
Wires tools to use runtime filesystem resolution: adds getFs(context?), updates tool execute handlers to accept a context param, routes all FS ops through resolved fs, enforces fs.readOnly at runtime, and uses hasFilesystemConfig() when deciding to register FS tools. Introduces FilesystemNotAvailableError handling and propagates WorkspaceError where appropriate.
Workspace Tests
packages/core/src/workspace/workspace.test.ts
Adds tests covering resolver-based configs: per-request selection, async resolvers, fallback to static FS, mounts/error cases, and logger behavior.
Workspace Tools Tests
packages/core/src/workspace/tools/tools.test.ts, packages/core/src/agent/__tests__/workspace-tool-context.test.ts
Adds tests for tool wiring with resolvers, per-request filesystem selection (admin vs user), and enforcement of read-only constraints for write operations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature being introduced: dynamic filesystem resolver support.
Linked Issues check ✅ Passed All objectives from issue #13133 are met: filesystem now accepts a resolver function receiving requestContext, enables per-request filesystem selection, and maintains backward compatibility with static instances.
Out of Scope Changes check ✅ Passed All changes directly support the dynamic filesystem resolver feature; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/core/src/workspace/workspace.ts (1)

514-523: Logger not propagated to dynamically resolved filesystems.

Filesystems created by the resolver won't have the Mastra logger set (since __setLogger only propagates to this._fs). If the resolver creates MastraFilesystem subclasses, their logging will be silent.

Consider calling __setLogger on the resolved filesystem within resolveFilesystem() if a logger has been set on the workspace. This would require storing the logger reference.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/workspace/workspace.ts` around lines 514 - 523,
resolveFilesystem currently returns filesystems from _filesystemResolver without
propagating the workspace logger, so dynamically resolved MastraFilesystem
instances remain un-logged; store the workspace logger when set (e.g., a private
field) and, inside resolveFilesystem, after obtaining the result from
_filesystemResolver (or when returning this._fs), call
result.__setLogger(this._logger) (or similar) if a logger exists and the
returned object has __setLogger, ensuring both dynamically resolved and default
filesystems receive the workspace logger.
packages/core/src/workspace/tools/tools.ts (1)

86-97: Misleading error when resolver is configured but requestContext is absent.

When a workspace uses a resolver-based filesystem, if a tool is invoked without requestContext in the context, getFs() falls through to the workspace.filesystem check (line 95), which is undefined for resolver-based workspaces. The thrown FilesystemNotAvailableError message says "Workspace does not have a filesystem configured", which is incorrect — a resolver is configured, but the context is missing.

Consider adding an explicit check:

Proposed fix for a clearer error message
   async function getFs(context?: ToolExecutionContext): Promise<WorkspaceFilesystem> {
     if (context?.requestContext) {
       const fs = await workspace.resolveFilesystem({ requestContext: context.requestContext });
       if (!fs) throw new FilesystemNotAvailableError();
       return fs;
     }
+    // If a resolver is configured but no requestContext was provided, give a clear error
+    if (workspace.hasFilesystemConfig() && !workspace.filesystem) {
+      throw new WorkspaceError(
+        'Filesystem resolver requires requestContext, but none was provided',
+        'NO_REQUEST_CONTEXT',
+      );
+    }
     if (!workspace.filesystem) throw new FilesystemNotAvailableError();
     return workspace.filesystem;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/workspace/tools/tools.ts` around lines 86 - 97, The current
getFs function throws FilesystemNotAvailableError with a misleading message when
a resolver-based filesystem is configured but no requestContext is provided;
update getFs to explicitly detect if workspace.resolveFilesystem (the resolver)
exists and, when context?.requestContext is missing, throw a clearer error
(e.g., a new or augmented FilesystemNotAvailableError message) that states the
resolver requires a requestContext rather than saying the workspace has no
filesystem; adjust error creation or message in getFs (referencing getFs,
workspace.resolveFilesystem, workspace.filesystem, and
FilesystemNotAvailableError) so callers can distinguish "no filesystem
configured" vs "resolver requires requestContext".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/dynamic-filesystem-resolver.md:
- Line 5: Update the changeset text to show the public API before/after for the
Workspace `filesystem` option (example: previous static `filesystem:
WorkspaceFilesystem` vs new resolver form `filesystem: ({ requestContext }) =>
WorkspaceFilesystem`), remove internal implementation details about tool
injection and runtime enforcement, and instead clearly state the user-facing
outcome: per-request filesystem routing enabled and common use cases
(multi-tenant routing, per-request mounts). Also add a short "Why" sentence
explaining the benefit (flexible routing of filesystem access per request) and
mark this as a minor feature.

In `@packages/core/src/workspace/workspace.ts`:
- Around line 396-401: The current branch treats any function in
config.filesystem as a resolver, but class constructors would match typeof ===
'function' and be misinterpreted; update the conditional around
config.filesystem to detect and reject class constructors (e.g., use
Function.prototype.toString to check for /^class\s/ or check prototype
characteristics) and throw a clear error when a class is passed, otherwise
assign this._filesystemResolver as before; keep the else branch that assigns
this._fs unchanged. Ensure you update the logic that sets
this._filesystemResolver and reference config.filesystem,
this._filesystemResolver, and this._fs when making the change.

---

Nitpick comments:
In `@packages/core/src/workspace/tools/tools.ts`:
- Around line 86-97: The current getFs function throws
FilesystemNotAvailableError with a misleading message when a resolver-based
filesystem is configured but no requestContext is provided; update getFs to
explicitly detect if workspace.resolveFilesystem (the resolver) exists and, when
context?.requestContext is missing, throw a clearer error (e.g., a new or
augmented FilesystemNotAvailableError message) that states the resolver requires
a requestContext rather than saying the workspace has no filesystem; adjust
error creation or message in getFs (referencing getFs,
workspace.resolveFilesystem, workspace.filesystem, and
FilesystemNotAvailableError) so callers can distinguish "no filesystem
configured" vs "resolver requires requestContext".

In `@packages/core/src/workspace/workspace.ts`:
- Around line 514-523: resolveFilesystem currently returns filesystems from
_filesystemResolver without propagating the workspace logger, so dynamically
resolved MastraFilesystem instances remain un-logged; store the workspace logger
when set (e.g., a private field) and, inside resolveFilesystem, after obtaining
the result from _filesystemResolver (or when returning this._fs), call
result.__setLogger(this._logger) (or similar) if a logger exists and the
returned object has __setLogger, ensuring both dynamically resolved and default
filesystems receive the workspace logger.

…and update changeset

Signed-off-by: intojhanurag <aojharaj2004@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/core/src/workspace/workspace.ts (2)

509-531: resolveFilesystem does not validate that requestContext is defined.

If a caller passes { requestContext: undefined as any }, the resolver receives undefined and will likely throw a confusing error inside the resolver function (e.g., Cannot read properties of undefined (reading 'get')). Consider a defensive guard, especially since this is a public API surface.

This is low risk since TypeScript enforces the type at compile time, but runtime callers (e.g., the tool layer wiring) could pass unexpected values.

🛡️ Optional defensive guard
  async resolveFilesystem({
    requestContext,
  }: {
    requestContext: RequestContext;
  }): Promise<WorkspaceFilesystem | undefined> {
    if (this._filesystemResolver) {
+     if (!requestContext) {
+       throw new WorkspaceError(
+         'requestContext is required when using a filesystem resolver',
+         'INVALID_CONFIG',
+         this.id,
+       );
+     }
      return await this._filesystemResolver({ requestContext });
    }
    return this._fs;
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/workspace/workspace.ts` around lines 509 - 531,
resolveFilesystem currently passes whatever is given to this._filesystemResolver
and can forward an undefined requestContext; add a defensive guard at the top of
resolveFilesystem to validate that the parameter requestContext is defined and
of expected shape (RequestContext) and throw a clear, descriptive error (e.g.,
"resolveFilesystem requires a valid requestContext") if it is not, before
calling this._filesystemResolver or returning this._fs; reference the
resolveFilesystem method and the _filesystemResolver field when adding this
check so runtime callers get a helpful error instead of an internal "cannot read
property" crash.

83-92: filesystem getter returns undefined when a resolver is used — document this clearly.

The filesystem getter (Line 486-490) returns this._fs which is undefined when a resolver is configured. This is tested and intentional, but several other methods also silently return empty/partial results in resolver mode:

  • getPathContext() — no filesystem info
  • getInfo() — no filesystem section
  • rebuildSearchIndex() / auto-indexing — no-op
  • skills getter — falls back to LocalSkillSource

This is architecturally sound (static operations can't use per-request resolution), but consider adding a note in the filesystem getter JSDoc that it returns undefined when using a resolver, and to use resolveFilesystem() instead.

Also applies to: 486-490

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/workspace/workspace.ts` around lines 83 - 92, Update the
JSDoc for the filesystem getter to explicitly state that when a
WorkspaceFilesystemResolver is configured the getter returns undefined (because
_fs is only set for static filesystems) and to instruct callers to use
resolveFilesystem(requestContext) for per-request resolution; reference the
filesystem getter and resolveFilesystem() by name and mention that methods like
getPathContext(), getInfo(), rebuildSearchIndex(), and the skills getter operate
without filesystem info in resolver mode so consumers should call
resolveFilesystem() at execution time for dynamic behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/workspace/workspace.ts`:
- Around line 509-531: resolveFilesystem currently passes whatever is given to
this._filesystemResolver and can forward an undefined requestContext; add a
defensive guard at the top of resolveFilesystem to validate that the parameter
requestContext is defined and of expected shape (RequestContext) and throw a
clear, descriptive error (e.g., "resolveFilesystem requires a valid
requestContext") if it is not, before calling this._filesystemResolver or
returning this._fs; reference the resolveFilesystem method and the
_filesystemResolver field when adding this check so runtime callers get a
helpful error instead of an internal "cannot read property" crash.
- Around line 83-92: Update the JSDoc for the filesystem getter to explicitly
state that when a WorkspaceFilesystemResolver is configured the getter returns
undefined (because _fs is only set for static filesystems) and to instruct
callers to use resolveFilesystem(requestContext) for per-request resolution;
reference the filesystem getter and resolveFilesystem() by name and mention that
methods like getPathContext(), getInfo(), rebuildSearchIndex(), and the skills
getter operate without filesystem info in resolver mode so consumers should call
resolveFilesystem() at execution time for dynamic behavior.

@intojhanurag intojhanurag marked this pull request as draft February 17, 2026 18:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Requested: Support dynamic filesystem resolution via requestContext in Workspace

1 participant

Comments