Skip to main content

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

TypeScriptsrc/mastra/index.ts
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

storage:
FactoryStorage
Application and agent storage. Use PgFactoryStorage for Postgres or LibSQLFactoryStorage for local storage.
auth?:
IMastraAuthProvider | null
Authentication provider with Server and Studio support. Defaults to Mastra platform authentication. Pass null to disable authentication for local development.
vector?:
MastraVector
Vector store for recall search. When omitted, the SDK mount resolves its default.
pubsub?:
PubSub
Distributed event bus. Omitted uses the in-process default.
publicUrl?:
string
= http://localhost:4111
Public origin used for integration and authentication callbacks. Configure it to match the server topology.
allowedOrigins?:
string[]
Additional origins permitted for credentialed UI requests when the UI is served separately.
sandbox?:
(ctx: FactorySandboxContext) => MastraSandbox
Constructs a sandbox for a session. Omitted disables repository sandboxes.
sandboxStart?:
'lazy' | 'eager'
= lazy
Start on the first command, or when the session workspace is first resolved.
dispatcher?:
MastraFactoryDispatcherConfig
Background dispatch configuration. maxInFlight is a per-replica concurrency budget.
stateSecret?:
string
Stable integration OAuth state-signing secret. Omitted generates a temporary secret, rejected by integrations requiring a stable signer.
secretEncryption?:
FactorySecretEncryption
Encrypts persisted credentials and integration settings. Omitted enables plaintext compatibility and warns when auth is enabled.
integrations?:
FactoryIntegration[]
Explicit integrations. Platform credentials supply missing GitHub and Linear integrations.
configVersion?:
string
= factory-config-v1
Configuration version recorded in audit entries. Does not change rule behavior.
boards?:
readonly InstalledBoard[]
Additional board definitions. IDs must be unique; work and review are reserved.
includeDefaultBoards?:
boolean
= true
Whether built-in Work and Review boards are installed.
platform?:
{ githubAppSlug?: string }
Identifies the deployment-owned GitHub App so its own writes are recognized.

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

  1. Construct MastraFactory with storage and the capabilities your server needs.
  2. Call prepare() once.
  3. Construct and export Mastra using the returned configuration.
  4. Call finalize().
  5. 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 fieldTypeMeaning
sessionIdstringStable session identity. Use it for the provider's sandbox identity or local session directory.
repoFullNamestring | undefinedRepository owner and name when the session is repository-backed.
setupCommandstring | undefinedConfigured repository setup command, also part of template identity.
getRepositoryAccessFunction or undefinedResolves 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/factoryExportMain configuration
/integrations/github/integrationGithubIntegrationGitHub App credentials, optional webhook secret and event rules.
/integrations/linear/integrationLinearIntegrationOAuth client credentials and optional event rules.
/integrations/slack/integrationSlackIntegrationSigning secret, bot token, account-linking credentials, and public origins.
/integrations/platform/github/integrationPlatformGithubIntegrationPlatform configuration from the environment.
/integrations/platform/linear/integrationPlatformLinearIntegrationPlatform configuration from the environment.
/integrations/workos/integrationWorkOSAuditIntegrationWorkOS 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.

FieldRequiredDescription
idYesUnique board identifier. work and review are reserved for built-in boards.
titleYesDisplay name in the UI.
initialPhaseYesID of an existing phase with kind: 'resting'.
phasesYesNonempty map of phase IDs to phase definitions.
toolsNoTool names mapped to onResult handlers.
transitionPolicyNoFunction 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

FieldRequiredDescription
titleYesPhase display name.
kindYesresting, working, or terminal.
roleFor working phasesAgent role for this phase. Not allowed on resting or terminal phases.
nextNoOne destination phase without an outcome label.
outcomesNoMap of outcome labels to destination phases.
onEnterNoHandlers for entering the phase, keyed by source.
onExitNoHandlers 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 typeEffect
invokeSkillStart an agent with either prompt or skillName. Its role must match the working phase.
transitionRequest a move to a declared board and stage, subject to validation and policy.
upsertLinkedWorkItemCreate or update a linked work item.
sendMessageSend a message to a session.
notifySend a notification to the bound session, with title, optional body, and optional level.
rejectReject 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:

FieldDescription
toolNameName of the completed tool.
threadIdThread in which the tool ran.
assistantMessageIdAssistant message associated with the call.
toolCallIdIdentifier of the tool call.
result.statussuccess or error.
result.valueJSON-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: true records 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.