MastraFactory
MastraFactory assembles Factory storage domains, integrations, boards, sessions, and background work into a Mastra application.
Use Get started for the complete generated server. The example below demonstrates the constructor and lifecycle with local storage and local execution.
Usage example
import { join } from 'node:path'
import { Mastra } from '@mastra/core'
import { LocalSandbox } from '@mastra/core/workspace'
import { MastraFactory } from '@mastra/factory'
import { LibSQLFactoryStorage } from '@mastra/libsql'
const factory = new MastraFactory({
storage: new LibSQLFactoryStorage({
id: 'factory-storage',
url: 'file:./factory.db',
}),
sandbox: ({ sessionId }) =>
new LocalSandbox({ workingDirectory: join(process.cwd(), 'sandboxes', sessionId) }),
})
export const mastra = new Mastra(await factory.prepare())
await factory.finalize()Factory defaults to Mastra platform authentication when you omit auth. To use another provider, pass one that supports both Server and Studio authentication. See Auth for provider configuration.
Connect GitHub and a model provider to start repository work.
Constructor parameters
Methods
prepare()
Assemble configuration before constructing Mastra. Call once per Factory instance. A second call throws.
const mastraOptions = await factory.prepare()
Returns: Promise<MastraArgs>, the constructor configuration for Mastra, including assembled controllers, server routes, authentication, storage, and workers. Export a new Mastra(...) instance from the entry file as shown in the usage example.
finalize()
Initialize the controller and start Factory work after the Mastra instance has been constructed.
await factory.finalize()
Returns: Promise<void>. Calling before preparation throws.
shutdown()
Stop background dispatch owned by the Factory runtime during server shutdown.
await factory.shutdown()
Returns: Promise<void>. The server remains responsible for the Mastra instance and its other workers.
Lifecycle
- Construct
MastraFactorywith storage and the capabilities your server needs. - Call
prepare()once. - Construct and export
Mastrausing the returned configuration. - Call
finalize(). - Call
shutdown()as part of server shutdown.
Sandbox configuration
MastraFactorySandboxConfig is a function from session context to MastraSandbox. Return the sandbox instance without starting it. Factory manages startup and repository setup.
| Context field | Type | Meaning |
|---|---|---|
sessionId | string | Stable session identity. Use it for the provider's sandbox identity or local session directory. |
repoFullName | string | undefined | Repository owner and name when the session is repository-backed. |
setupCommand | string | undefined | Configured repository setup command, also part of template identity. |
getRepositoryAccess | Function or undefined | Resolves repository access with a fresh short-lived credential. Use it when preparing private repository templates. |
Local sandboxes should use a per-session directory. Remote providers should honor the session ID when creating or resuming a sandbox. Return a MastraSandbox subclass so Factory can use its startup lifecycle. Implementing only WorkspaceSandbox is insufficient.
The previous configuration object with machine, workdir, and maxSandboxes is obsolete. prepare() no longer creates the documented sandbox fleet. See Sandboxes for generated-server provider selection.
Integrations
Pass FactoryIntegration implementations in integrations. Integrations can contribute routes, intake, version control, agent and session tools, workers, channels, diagnostics, and audit behavior. Each integration needs a unique ID.
Import built-in integrations from these package subpaths:
Import under @mastra/factory | Export | Main configuration |
|---|---|---|
/integrations/github/integration | GithubIntegration | GitHub App credentials, optional webhook secret and event rules. |
/integrations/linear/integration | LinearIntegration | OAuth client credentials and optional event rules. |
/integrations/slack/integration | SlackIntegration | Signing secret, bot token, account-linking credentials, and public origins. |
/integrations/platform/github/integration | PlatformGithubIntegration | Platform configuration from the environment. |
/integrations/platform/linear/integration | PlatformLinearIntegration | Platform configuration from the environment. |
/integrations/workos/integration | WorkOSAuditIntegration | WorkOS client and return URL for audit integration. |
When MASTRA_PLATFORM_ACCESS_TOKEN or MASTRA_PLATFORM_SECRET_KEY is present, prepare() fills missing github and linear integration IDs with Platform implementations. Explicit integrations take precedence for their IDs. This condition differs from Platform sandbox selection.
Board definitions
Import defineBoard from @mastra/factory and pass the returned definition in the constructor's boards array. See Boards and rules for configuration examples.
| Field | Required | Description |
|---|---|---|
id | Yes | Unique board identifier. work and review are reserved for built-in boards. |
title | Yes | Display name in the UI. |
initialPhase | Yes | ID of an existing phase with kind: 'resting'. |
phases | Yes | Nonempty map of phase IDs to phase definitions. |
tools | No | Tool names mapped to onResult handlers. |
transitionPolicy | No | Function that allows or rejects a requested move. |
Work and Review are installed by default. Set includeDefaultBoards: false on MastraFactory to install only custom boards. Reserved IDs still apply. Custom boards can't replace built-in definitions.
Phase fields
| Field | Required | Description |
|---|---|---|
title | Yes | Phase display name. |
kind | Yes | resting, working, or terminal. |
role | For working phases | Agent role for this phase. Not allowed on resting or terminal phases. |
next | No | One destination phase without an outcome label. |
outcomes | No | Map of outcome labels to destination phases. |
onEnter | No | Handlers for entering the phase, keyed by source. |
onExit | No | Handlers for leaving the phase, keyed by source. |
Resting phases wait for a person or event, while working phases assign an agent role. Terminal phases mark work as finished. Factory then stops its sessions and releases held resources.
A phase can't declare both next and outcomes. Every destination must reference an existing phase. These fields define allowed transitions without performing them. The returned definition exposes allowsTransition(from, to) to check whether a move is declared.
Rules
Configure phase handlers and tool-result handlers through defineBoard(). Configure external-event handlers on the corresponding integration. The former defaultFactoryRules() API and MastraFactory.rules constructor option are no longer supported.
Rule handlers
Phase handlers are keyed by source: manual, issue, pullRequest, or linearIssue. Each onEnter or onExit handler receives a read-only FactoryStageRuleContext. A handler returns one decision or undefined, synchronously or through a promise.
Common context fields include item, board, actor, ingress, itemRevision, and configVersion. Phase context also includes source, stage, fromStage, and toStage. ingress.id identifies the event being processed.
| Decision type | Effect |
|---|---|
invokeSkill | Start an agent with either prompt or skillName. Its role must match the working phase. |
transition | Request a move to a declared board and stage, subject to validation and policy. |
upsertLinkedWorkItem | Create or update a linked work item. |
sendMessage | Send a message to a session. |
notify | Send a notification to the bound session, with title, optional body, and optional level. |
reject | Reject the operation with a code and reason. |
Action decisions require an idempotencyKey, except for reject. Use a stable key derived from the event ID and action so processing a duplicate event doesn't repeat the action. Direct external calls inside handlers don't receive that protection.
Tool results
Declare handlers as tools: { toolName: { onResult: handler } } on the board. A handler receives FactoryToolResultRuleContext, which adds these fields to the common context:
| Field | Description |
|---|---|
toolName | Name of the completed tool. |
threadId | Thread in which the tool ran. |
assistantMessageId | Assistant message associated with the call. |
toolCallId | Identifier of the tool call. |
result.status | success or error. |
result.value | JSON-compatible result whose structure depends on the tool. |
Tool-result handlers return the decision types listed above. A handler reacts to an available tool but doesn't add that tool to the agent. If the board has no handler for a tool result, Factory doesn't produce a rule decision.
The built-in Work board handles approved submit_plan results from a planning agent. Custom boards don't inherit or override this handler.
Transition policy
transitionPolicy(context) returns one of the following, synchronously or through a promise:
undefined: Apply Factory's remaining checks without an additional policy decision.{ type: 'allow', triageType?, accept? }: Allow the move subject to remaining checks.accept: truerecords acceptance.{ type: 'reject', code, reason }: Reject the move with an explanation.
The immutable context includes fromStage, toStage, isHumanTransition, initialEntry, reenter, and the work item. Policies can't authorize undeclared moves or bypass Factory's other checks.
For example, add this property alongside phases in the Quality board definition to require a person to move the card to Done:
transitionPolicy: context => {
if (context.toStage === 'done' && !context.isHumanTransition) {
return {
type: 'reject',
code: 'approval_required',
reason: 'A person must approve the quality check.',
}
}
},
Configuration version
Set configVersion on MastraFactory to identify the deployed configuration in audit records and rule context. The default is factory-config-v1. Changing the value doesn't change which handlers run.