github mastra-ai/mastra @mastra/core@1.5.0
February 19, 2026

7 hours ago

Highlights

Core Harness: A Reusable Orchestration Layer for Agent Apps

A new generic Harness in @mastra/core provides a foundation for building agent-powered applications with modes, state management, built-in tools (ask_user, submit_plan), subagent support, Observational Memory integration, model discovery, permission-aware tool approval, and event-driven/thread/heartbeat management.

Workspace Capability Upgrades (Security, Discovery, and Search)

Workspaces gain least-privilege filesystem access via LocalFilesystem.allowedPaths (plus runtime updates with setAllowedPaths()), expanded glob-based configuration for file listing/indexing/skill discovery, and a new regex search tool mastra_workspace_grep to complement semantic search.

Better Tool I/O and Streaming Behavior in the Agent Loop

Tools can now define toModelOutput to transform tool results into model-friendly content while preserving raw outputs in storage, and workspace tools now return raw text (moving structured metadata to data-workspace-metadata stream chunks) to reduce token usage. Streaming reliability also improves (correct chunk types for tool errors, onChunk receives raw Mastra chunks, agent loop continues after tool errors).

Changelog

@mastra/core@1.5.0

Minor Changes

  • Added allowedPaths option to LocalFilesystem for granting agents access to specific directories outside basePath without disabling containment. (#13054)

    const workspace = new Workspace({
      filesystem: new LocalFilesystem({
        basePath: './workspace',
        allowedPaths: ['/home/user/.config', '/home/user/documents'],
      }),
    });

    Allowed paths can be updated at runtime using setAllowedPaths():

    workspace.filesystem.setAllowedPaths(prev => [...prev, '/home/user/new-dir']);

    This is the recommended approach for least-privilege access — agents can only reach the specific directories you allow, while containment stays enabled for everything else.

  • Added generic Harness class for orchestrating agents with modes, state management, built-in tools (ask_user, submit_plan), subagent support, Observational Memory integration, model discovery, and permission-aware tool approval. The Harness provides a reusable foundation for building agent-powered applications with features like thread management, heartbeat monitoring, and event-driven architecture. (#13245)

  • Added glob pattern support for workspace configuration. The list_files tool now accepts a pattern parameter for filtering files (e.g., **/*.ts, src/**/*.test.ts). autoIndexPaths accepts glob patterns like ./docs/**/*.md to selectively index files for BM25 search. Skills paths support globs like ./**/skills to discover skill directories at any depth, including dot-directories like .agents/skills. (#13023)

    list_files tool with pattern:

    // Agent can now use glob patterns to filter files
    const result = await workspace.tools.workspace_list_files({
      path: '/',
      pattern: '**/*.test.ts',
    });

    autoIndexPaths with globs:

    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: './project' }),
      bm25: true,
      // Only index markdown files under ./docs
      autoIndexPaths: ['./docs/**/*.md'],
    });

    Skills paths with globs:

    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: './project' }),
      // Discover any directory named 'skills' within 4 levels of depth
      skills: ['./**/skills'],
    });

    Note: Skills glob discovery walks up to 4 directory levels deep from the glob's static prefix. Use more specific patterns like ./src/**/skills to narrow the search scope for large workspaces.

  • Added direct skill path discovery — you can now pass a path directly to a skill directory or SKILL.md file in the workspace skills configuration (e.g., skills: ['/path/to/my-skill'] or skills: ['/path/to/my-skill/SKILL.md']). Previously only parent directories were supported. Also improved error handling when a configured skills path is inaccessible (e.g., permission denied), logging a warning instead of breaking discovery for all skills. (#13031)

  • Add optional instruction field to ObservationalMemory config types (#13240)

    Adds instruction?: string to ObservationalMemoryObservationConfig and ObservationalMemoryReflectionConfig interfaces, allowing external consumers to pass custom instructions to observational memory.

  • Added typed workspace providers — workspace.filesystem and workspace.sandbox now return the concrete types you passed to the constructor, improving autocomplete and eliminating casts. (#13021)

    When mounts are configured, workspace.filesystem returns a typed CompositeFilesystem<TMounts> with per-key narrowing via mounts.get().

    Before:

    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: '/tmp' }),
      sandbox: new E2BSandbox({ timeout: 60000 }),
    });
    workspace.filesystem; // WorkspaceFilesystem | undefined
    workspace.sandbox; // WorkspaceSandbox | undefined

    After:

    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: '/tmp' }),
      sandbox: new E2BSandbox({ timeout: 60000 }),
    });
    workspace.filesystem; // LocalFilesystem
    workspace.sandbox; // E2BSandbox
    
    // Mount-aware workspaces get typed per-key access:
    const ws = new Workspace({
      mounts: { '/local': new LocalFilesystem({ basePath: '/tmp' }) },
    });
    ws.filesystem.mounts.get('/local'); // LocalFilesystem
  • Added support for Vercel AI Gateway in the model router. You can now use model: 'vercel/google/gemini-3-flash' with agents and it will route through the official AI SDK gateway provider. (#13149)

  • Added toModelOutput support to the agent loop. Tool definitions can now include a toModelOutput function that transforms the raw tool result before it's sent to the model, while preserving the raw result in storage. This matches the AI SDK toModelOutput convention — the function receives the raw output directly and returns { type: 'text', value: string } or { type: 'content', value: ContentPart[] }. (#13171)

    import { createTool } from '@mastra/core/tools';
    import { z } from 'zod';
    
    const weatherTool = createTool({
      id: 'weather',
      inputSchema: z.object({ city: z.string() }),
      execute: async ({ city }) => ({
        city,
        temperature: 72,
        conditions: 'sunny',
        humidity: 45,
        raw_sensor_data: [0.12, 0.45, 0.78],
      }),
      // The model sees a concise summary instead of the full JSON
      toModelOutput: output => ({
        type: 'text',
        value: `${output.city}: ${output.temperature}°F, ${output.conditions}`,
      }),
    });
  • Added mastra_workspace_grep workspace tool for regex-based content search across files. This complements the existing semantic search tool by providing direct pattern matching with support for case-insensitive search, file filtering by extension, context lines, and result limiting. (#13010)

    The tool is automatically available when a workspace has a filesystem configured:

    import { Workspace, WORKSPACE_TOOLS } from '@mastra/core/workspace';
    import { LocalFilesystem } from '@mastra/core/workspace';
    
    const workspace = new Workspace({
      filesystem: new LocalFilesystem({ basePath: './my-project' }),
    });
    
    // The grep tool is auto-injected and available as:
    // WORKSPACE_TOOLS.SEARCH.GREP → 'mastra_workspace_grep'
  • Removed outputSchema from workspace tools to return raw text instead of JSON, optimizing for token usage and LLM performance. Structured metadata that was previously returned in tool output is now emitted as data-workspace-metadata chunks via writer.custom(), keeping it available for UI consumption without passing it to the LLM. Tools are also extracted into individual files and can be imported directly (e.g. import { readFileTool } from '@mastra/core/workspace'). (#13166)

Patch Changes

  • dependencies updates: (#13127)

  • dependencies updates: (#13167)

  • Export AnyWorkspace type from @mastra/core/workspace for accepting any Workspace regardless of generic parameters. Updates Agent and Mastra to use AnyWorkspace so workspaces with typed mounts/sandbox (e.g. E2BSandbox, GCSFilesystem) are accepted without type errors. (#13155)

  • Update provider registry and model documentation with latest models and providers (e37ef84)

  • Fixed skill processor tools (skill-activate, skill-search, skill-read-reference, skill-read-script, skill-read-asset) being incorrectly suspended for approval when requireToolApproval: true is set. These internal tools now bypass the approval check and execute directly. (#13160)

  • Fixed a bug where requestContext metadata was not propagated to child spans. When using requestContextKeys, only root spans were enriched with request context values — child spans (e.g. agent_run inside a workflow) were missing them. All spans in a trace are now correctly enriched. Fixes #12818. (#12819)

  • Fixed semantic recall search in Mastra Studio returning no results when using non-default embedding dimensions (e.g., fastembed with 384-dim). The SemanticRecall processor now probes the embedder for its actual output dimension, ensuring the vector index name matches between write and read paths. Previously, the processor defaulted to a 1536-dim index name regardless of the actual embedder, causing a mismatch with the dimension-aware index name used by Studio's search. Fixes #13039 (#13059)

  • Fixed CompositeFilesystem instructions: agents and tools no longer receive an incorrect claim that files written via workspace tools are accessible at sandbox paths. The instructions now accurately describe only the available mounted filesystems. (#13221)

  • Fixed onChunk callback to receive raw Mastra chunks instead of AI SDK v5 converted chunks for tool results. Also added missing onChunk calls for tool-error chunks and tool-result chunks in mixed-error scenarios. (#13243)

  • Fixed tool execution errors stopping the agentic loop. The agent now continues after tool errors, allowing the model to see the error and retry with corrected arguments. (#13242)

  • Added runtime requestContext forwarding to tool executions. (#13094)

    Tools invoked within agentic workflow steps now receive the caller's requestContext — including authenticated API clients, feature flags, and user metadata set by middleware. Runtime requestContext is preferred over build-time context when both are available.

    Why: Previously, requestContext values were silently dropped in two places: (1) the workflow loop stream created a new empty RequestContext instead of forwarding the caller's, and (2) createToolCallStep didn't pass requestContext in tool options. This aligns both the agent generate/stream and agentic workflow paths with the agent network path, where requestContext was already forwarded correctly.

    Before: Tools received an empty requestContext, losing all values set by the workflow step.

    // requestContext with auth data set in workflow step
    requestContext.set('apiClient', authedClient);
    // tool receives empty RequestContext — apiClient is undefined

    After: Pass requestContext via MastraToolInvocationOptions and tools receive it.

    // requestContext with auth data flows through to the tool
    requestContext.set('apiClient', authedClient);
    // tool receives the same RequestContext — apiClient is available

    Fixes #13088

  • Fixed tsc out-of-memory crash caused by step-schema.d.ts expanding to 50k lines. Added explicit type annotations to all exported Zod schema constants, reducing declaration output from 49,729 to ~500 lines without changing runtime behavior. (#13229)

  • Fixed TypeScript type generation hanging or running out of memory when packages depend on @mastra/core tool types. Changed ZodLikeSchema from a nominal union type to structural typing, which prevents TypeScript from performing deep comparisons of zod v3/v4 type trees during generic inference. (#13239)

  • Fixed tool execution errors being emitted as tool-result instead of tool-error in fullStream. Previously, when a tool's execute function threw an error, the error was caught and returned as a value, causing the stream to emit a tool-result chunk containing the error object. Now errors are properly propagated, so the stream emits tool-error chunks, allowing consumers (including the @mastra/ai-sdk conversion pipeline) to correctly distinguish between successful tool results and failed tool executions. Fixes #13123. (#13147)

  • Fixed thread title not being generated for pre-created threads. When threads were created before starting a conversation (e.g., for URL routing or storing metadata), the title stayed as a placeholder because the title generation condition checked whether the thread existed rather than whether it had a title. Threads created without an explicit title now get an empty title instead of a placeholder, and title generation fires whenever a thread has no title. Resolves #13145. (#13151)

  • Fixed inputData in dowhile and dountil loop condition functions to be properly typed as the step's output schema instead of any. This means you no longer need to manually cast inputData in your loop conditions — TypeScript will now correctly infer the type from your step's outputSchema. (#12977)

  • Migrated MastraCode from the prototype harness to the generic CoreHarness from @mastra/core. The createMastraCode function is now fully configurable with optional parameters for modes, subagents, storage, tools, and more. Removed the deprecated prototype harness implementation. (#13245)

  • Fixed the writer object being undefined in processOutputStream, allowing output processors to emit custom events to the stream during chunk processing. This enables use cases like streaming moderation results back to the client. (#13056)

  • Fixed sub-agent tool approval resume flow. When a sub-agent tool required approval and was approved, the agent would restart from scratch instead of resuming, causing an infinite loop. The resume data is now correctly passed through for agent tools so they properly resume after approval. (#13241)

  • Dataset schemas now appear in the Edit Dataset dialog. Previously the inputSchema and groundTruthSchema fields were not passed to the dialog, so editing a dataset always showed empty schemas. (#13175)

    Schema edits in the JSON editor no longer cause the cursor to jump to the top of the field. Typing {"type": "object"} in the schema editor now behaves like a normal text input instead of resetting on every keystroke.

    Validation errors are now surfaced when updating a dataset schema that conflicts with existing items. For example, adding a required: ["name"] constraint when existing items lack a name field now shows "2 existing item(s) fail validation" in the dialog instead of silently dropping the error.

    Disabling a dataset schema from the Studio UI now correctly clears it. Previously the server converted null (disable) to undefined (no change), so the old schema persisted and validation continued.

    Workflow schemas fetched via client.getWorkflow().getSchema() are now correctly parsed. The server serializes schemas with superjson, but the client was using plain JSON.parse, yielding a {json: {...}} wrapper instead of the actual JSON Schema object.

  • Fixed network mode messages missing metadata for filtering. All internal network messages (sub-agent results, tool execution results, workflow results) now include metadata.mode: 'network' in their content metadata, making it possible to filter them from user-facing messages without parsing JSON content. Previously, consumers had to parse the JSON body of each message to check for isNetwork: true — now they can simply check message.content.metadata.mode === 'network'. Fixes #13106. (#13144)

  • Fixed sub-agent memory context pollution that caused 'Exhausted all fallback models' errors when using Observational Memory with sub-agents. The parent agent's memory context is now preserved across sub-agent tool execution. (#13051)

  • Fixed CompositeAuth losing public and protected route configurations from underlying auth providers. Routes marked as public or protected now work correctly when deployed to Mastra Cloud. (#13086)

  • Trimmed the agent experiment result output to only persist relevant fields instead of the entire FullOutput blob. The stored output now contains: text, object, toolCalls, toolResults, sources, files, usage, reasoningText, traceId, and error. (#13158)

    Dropped fields like steps, response, messages, rememberedMessages, request, providerMetadata, warnings, scoringData, suspendPayload, and other provider/debugging internals that were duplicated elsewhere or not useful for experiment evaluation.

  • Fixed .branch() condition receiving undefined inputData when resuming a suspended nested workflow after .map(). (#13055)

    Previously, when a workflow used .map() followed by .branch() and a nested workflow inside the branch called suspend(), resuming would fail with TypeError: Cannot read properties of undefined because the branch conditions were unnecessarily re-evaluated with stale data.

    Resume now skips condition re-evaluation for .branch() entries and goes directly to the correct suspended branch, matching the existing behavior for .parallel() entries.

    Fixes #12982

  • Updated dependencies [1415bcd]:

    • @mastra/schema-compat@1.1.1

@mastra/codemod@1.0.3

Patch Changes

  • Update internal dependency @clack/prompts to v1 (#13095)

@mastra/deployer@1.5.0

Patch Changes

@mastra/evals@1.1.2

Patch Changes

@mastra/loggers@1.0.2

Patch Changes

@mastra/mcp-docs-server@1.1.3

Patch Changes

@mastra/memory@1.4.0

Minor Changes

  • Add instruction property to observational memory configs (#13240)

    Adds optional instruction field to ObservationConfig and ReflectionConfig that allows users to extend the built-in observer/reflector system prompts with custom guidance.

    Example:

    const memory = new ObservationalMemory({
      model: openai('gpt-4'),
      observation: {
        instruction: 'Focus on user preferences about food and dietary restrictions.',
      },
      reflection: {
        instruction: 'Prioritize consolidating health-related observations together.',
      },
    });

Patch Changes

  • dependencies updates: (#13167)

  • Reflection retry logic now attempts compression up to level 3, so reflections more consistently shrink to meet token limits (#13170)

    • Default target compression reduced from 50% to 25% (sliceTokenEstimate * 0.75), making automatic trimming less aggressive
    • tokensBuffered marker now reports the actual slice size rather than total observation tokens, giving accurate size monitoring

    These changes reduce failed reflections and make reported metrics match what is actually being processed.

  • Fixed a bug where the OM context window would jump to extremely high token counts (e.g. 16k → 114k) after observation activation. Two issues were causing this: (#13070)

    • Token counter included OM metadata parts: data-om-activation marker parts (which contain the full observation text, up to 150k+ characters) were being counted as message tokens when loaded from the database. These parts are never sent to the LLM and are now skipped during token counting.
    • Marker duplication on messages: Activation markers were being added to assistant messages twice — once by the AI SDK stream and once by the persistence layer — doubling every marker and compounding the token inflation. Both persistMarkerToMessage and persistMarkerToStorage now deduplicate by type + cycleId before adding a marker.
  • Fixed thread title not being generated for pre-created threads. When threads were created before starting a conversation (e.g., for URL routing or storing metadata), the title stayed as a placeholder because the title generation condition checked whether the thread existed rather than whether it had a title. Threads created without an explicit title now get an empty title instead of a placeholder, and title generation fires whenever a thread has no title. Resolves #13145. (#13151)

  • Fixed sub-agent memory context pollution that caused 'Exhausted all fallback models' errors when using Observational Memory with sub-agents. The parent agent's memory context is now preserved across sub-agent tool execution. (#13051)

  • Updated dependencies [252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 02dc07a, bb7262b, 1415bcd, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:

    • @mastra/core@1.5.0
    • @mastra/schema-compat@1.1.1

@mastra/playground-ui@12.0.0

Minor Changes

  • Various improvements for ongoing project (#13040)

Patch Changes

  • dependencies updates: (#12921)

  • dependencies updates: (#13100)

  • Fixed React error #310 crash when using observational memory in Mastra Studio. The chat view would crash when observation markers appeared alongside regular tool calls during streaming. (#13216)

  • Fixed dragged column appearing offset from cursor when mapping CSV columns in dataset import dialog (#13176)

  • Fixed schema form to apply changes only on Save click instead of every keystroke. Removed AgentPromptExperimentProvider in favor of inline prompt rendering. Switched hooks to use merged request context for proper request-scoped data fetching. (#13034)

  • Added a "Try to connect" button in the MCP client sidebar to preview available tools before creating. Fixed SSE response parsing for MCP servers returning event streams. (#13093)

  • Fix dataset import creating a new version per item. CSV and JSON import dialogs now use the batch insert endpoint so all imported items land on a single version. (#13214)

  • Fix experiment result detail panel showing output data under "Input" label, add missing Output section, and add Input column to experiment results list table. (#13165)

  • Updated style of Button and Select experimental variants (#13186)

  • Added requestContext support to listScorers for request-scoped scorer resolution (#13034)

  • Added mount picker for skill installation when multiple filesystem mounts are available. Skills table and detail page now show skill paths and mount labels. (#13031)

  • Removed unused Dataset Item Edit Dialog (#13199)

  • Hide Dataset Item History panel when item is edited (#13195)

  • Dataset schemas now appear in the Edit Dataset dialog. Previously the inputSchema and groundTruthSchema fields were not passed to the dialog, so editing a dataset always showed empty schemas. (#13175)

    Schema edits in the JSON editor no longer cause the cursor to jump to the top of the field. Typing {"type": "object"} in the schema editor now behaves like a normal text input instead of resetting on every keystroke.

    Validation errors are now surfaced when updating a dataset schema that conflicts with existing items. For example, adding a required: ["name"] constraint when existing items lack a name field now shows "2 existing item(s) fail validation" in the dialog instead of silently dropping the error.

    Disabling a dataset schema from the Studio UI now correctly clears it. Previously the server converted null (disable) to undefined (no change), so the old schema persisted and validation continued.

    Workflow schemas fetched via client.getWorkflow().getSchema() are now correctly parsed. The server serializes schemas with superjson, but the client was using plain JSON.parse, yielding a {json: {...}} wrapper instead of the actual JSON Schema object.

  • Fixed "Tried to unmount a fiber that is already unmounted" error in the playground agent chat. Switching threads rapidly or creating new threads no longer causes this console error. (#13182)

  • Updated visuals of Dataset Items List empty state (#13203)

  • Updated workspace tool badges for execute command and list files tools. Execute command badge now shows running state for silent commands and correctly scopes output to individual tool calls during parallel execution. (#13166)

  • Updated dependencies [252580a, f8e819f, 5c75261, e27d832, e37ef84, 6fdd3d4, 10cf521, efdb682, 0dee7a0, 04c2c8e, 55a0ab1, 02dc07a, bb7262b, 1415bcd, cf1c6e7, cf1c6e7, 5ffadfe, 1e1339c, d03df73, 79b8f45, 9bbf08e, 0a25952, ffa5468, 55a0ab1, 3264a04, 6fdd3d4, 088d9ba, 74fbebd, ec36c0c, aea6217, b6a855e, ae408ea, 17e942e, 2015cf9, 7ef454e, 2be1d99, 2708fa1, ba74aef, ba74aef, ec53e89, 9b5a8cb, 607e66b, a215d06, 6909c74, 192438f]:

    • @mastra/core@1.5.0
    • @mastra/react@0.2.4
    • @mastra/client-js@1.5.0
    • @mastra/schema-compat@1.1.1
    • @mastra/ai-sdk@1.0.5

@mastra/schema-compat@1.1.1

Patch Changes

  • The zodToJsonSchema function now reliably detects and routes Zod v3 vs v4 schemas regardless of which version the ambient zod import resolves to. Previously, the detection relied on checking 'toJSONSchema' in z against the ambient z import, which could resolve to either v3 or v4 depending on the environment (monorepo vs global install). This caused v3 schemas to be passed to v4's toJSONSchema() (crashing with "Cannot read properties of undefined (reading 'def')") or v4 schemas to be passed to the v3 converter (producing schemas missing the type field).

    The fix explicitly imports z as zV4 from zod/v4 and routes based on the schema's own _zod property, making the behavior environment-independent.

    Also migrates all mastracode tool files from zod/v3 to zod imports now that the schema-compat fix supports both versions correctly.

@mastra/server@1.5.0

Minor Changes

  • Added workspace and skill storage domains with full CRUD, versioning, and implementations across LibSQL, Postgres, and MongoDB. (#13156)

Patch Changes

Don't miss a new mastra release

NewReleases is sending notifications on new releases.