Interface: MastraPluginConfig
Configuration accepted by the Mastra AppKit plugin.
Extends
Section titled “Extends”BasePluginConfig
Indexable
Section titled “Indexable”[
key:string]:unknown
Properties
Section titled “Properties”agentMaxSteps?
Section titled “agentMaxSteps?”
optionalagentMaxSteps?:number
Maximum LLM steps each agent gets per turn. One step = one round-trip to the underlying model (a tool call consumes a step, the final-text reply consumes one too). Applies to every agent registered through MastraPluginConfig.agents
- per-agent overrides aren’t surfaced yet because the same ceiling has been sufficient across every workload we’ve run.
Defaults to DEFAULT_AGENT_MAX_STEPS (25), sized to fit
a decomposed Genie turn (grounding + several ask_genie calls
prepare_chartper dataset + the final-text reply) with headroom for the model to chain a couple of follow-ups before answering. Mastra’s ownagent.generatedefault of 5 would cut multi-step orchestration off after 2-3 tool calls, so explicitly raising the ceiling here is what lets the agent-mode loop play out.
Lower when an unusually slow or expensive model makes long turns unaffordable; raise for exploratory workloads that need to drill deep into a dataset within a single turn.
agents?
Section titled “agents?”
optionalagents?:MastraAgentDefinition|Record<string,MastraAgentDefinition> |MastraAgentDefinition[]
Code-defined agents. Accepts three shapes for convenience:
- Record:
{ analyst: def, helper: def }- keys become the registered ids and the first key is the default. - Single definition:
def- registered underslugify(def.name)(or"default"whennameis omitted) and automatically marked as the default agent. - Array:
[def1, def2]- each registered underslugify(def.name)(oragent_${i}whennameis omitted); the first entry is the default.
Each entry becomes a Mastra Agent reachable at
/api/<plugin>/route/chat/<id> (the chat route also matches
:agentId). When agents is omitted entirely, the plugin
registers a single built-in default analyst so the bare
mastra() call still mounts a working chat endpoint.
Examples
Section titled “Examples”Single-agent shorthand
mastra({ agents: createAgent({ instructions: "..." }),});Array
mastra({ agents: [ createAgent({ name: "analyst", instructions: "..." }), createAgent({ name: "helper", instructions: "..." }), ],});Record (explicit ids)
mastra({ agents: { analyst: createAgent({ instructions: "..." }), helper: createAgent({ instructions: "..." }), }, defaultAgent: "analyst",});apiAccess?
Section titled “apiAccess?”
optionalapiAccess?:"scoped"|"full"
How much of the stock @mastra/express management API is reachable
through the plugin mount. @mastra/express registers its full route
table (agent inference plus admin / mutating routes: direct tool
execution, workflow control, raw memory read/write, telemetry, logs,
scores). AppKit already authenticates every request as the OBO user,
but nothing there restricts which of those operations the browser
client may invoke.
"scoped"(default): only the routes the chat client legitimately needs are dispatched to Mastra - agent inference (stream/generate/network), read-only agent metadata, this plugin’s own OBO- and resource-scoped/route/*routes (history / threads), and, when mcp is enabled, the MCP transport. Everything else (tool execution, workflow control, raw memory, telemetry, logs, scores, and other mutations) is rejected with403before it reaches Mastra."full": dispatch the entire stock Mastra API. Use only for a trusted first-party console that genuinely needs the management surface.
brand?
Section titled “brand?”
optionalbrand?:object
Optional brand context applied to charts produced by the built-in
render_data / prepare_chart tools. When set, the chart planner’s
Echarts output is themed with the brand’s palette (series colors derived
from colors.primary / colors.accent) and sans font
(typography.sans) instead of Echarts’ defaults. Omit for the default
Echarts look.
Pass the portable BrandContext shared across the UI and
libraries (e.g. brand.defaultBrandContext from @dbx-tools/shared-core,
or a customer brand) - the same object the email add-on and the UI
BrandProvider consume, so a host themes charts, email, and UI from one
source.
assets
Section titled “assets”assets:
object
assets.favicon
Section titled “assets.favicon”favicon:
string
assets.icon
Section titled “assets.icon”icon:
object
assets.icon.dark?
Section titled “assets.icon.dark?”
optionaldark?:string
assets.icon.light
Section titled “assets.icon.light”light:
string
assets.logo
Section titled “assets.logo”logo:
object
assets.logo.dark?
Section titled “assets.logo.dark?”
optionaldark?:string
assets.logo.light
Section titled “assets.logo.light”light:
string
colors
Section titled “colors”colors:
object=BrandColorsSchema
colors.accent
Section titled “colors.accent”accent:
string
colors.background
Section titled “colors.background”background:
string
colors.border
Section titled “colors.border”border:
string
colors.foreground
Section titled “colors.foreground”foreground:
string
colors.muted
Section titled “colors.muted”muted:
string
colors.primary
Section titled “colors.primary”primary:
string
colors.primaryHover
Section titled “colors.primaryHover”primaryHover:
string
colors.surface
Section titled “colors.surface”surface:
string
description
Section titled “description”description:
string
extensions
Section titled “extensions”extensions:
Record<string,unknown>
links:
object
links.documentation?
Section titled “links.documentation?”
optionaldocumentation?:string
links.repository?
Section titled “links.repository?”
optionalrepository?:string
links.website?
Section titled “links.website?”
optionalwebsite?:string
name:
string
schemaVersion
Section titled “schemaVersion”schemaVersion:
"1"
shortName
Section titled “shortName”shortName:
string
tagline
Section titled “tagline”tagline:
string
typography
Section titled “typography”typography:
object
typography.mono
Section titled “typography.mono”mono:
string
typography.sans
Section titled “typography.sans”sans:
string
voice:
object=BrandVoiceSchema
voice.audience
Section titled “voice.audience”audience:
string[]
voice.avoid
Section titled “voice.avoid”avoid:
string[]
voice.principles
Section titled “voice.principles”principles:
string[]
voice.tone
Section titled “voice.tone”tone:
string[]
defaultAgent?
Section titled “defaultAgent?”
optionaldefaultAgent?:string
Agent id used when the client doesn’t specify one (the bare,
un-suffixed history / suggestions routes resolve to it).
Defaults to the first key in agents (or "default" when
agents is omitted). Must match an id in agents when both are
set; a mismatch throws at setup with the available candidates.
defaultModel?
Section titled “defaultModel?”
optionaldefaultModel?:string|LanguageModelV1|LanguageModelV2|LanguageModelV3|LanguageModelV4|string&object| {apiKey?:string;headers?:Record<string,string>;id:`${string}/${string}`;url?:string; } | {apiKey?:string;headers?:Record<string,string>;modelId:string;providerId:string;url?:string; } |MastraLanguageModelV2|MastraLanguageModelV3|MastraLanguageModelV4|ModelWithRetries[] | ((__namedParameters) =>MastraModelConfig|ModelWithRetries[] |Promise<MastraModelConfig | ModelWithRetries[]>)
Plugin-level default model applied to every agent that omits its
own model. Mirrors AppKit’s agents({ defaultModel }).
string: shorthand for “use the OBO auto-resolver but swap themodelId” (e.g."databricks-claude-sonnet-4-6").- Any other Mastra
DynamicArgument<MastraModelConfig>: passed through verbatim. Use this when you need full control over auth orproviderId.
Resolution order per agent: def.model → defaultModel →
DATABRICKS_SERVING_ENDPOINT_NAME → built-in /serving-endpoints
resolver.
defaultModelFallbacks?
Section titled “defaultModelFallbacks?”
optionaldefaultModelFallbacks?: readonlystring[]
Priority-ordered list of endpoint names tried first when no
agent / plugin / env / request-override model id is set, ahead of
the dynamic score-classified catalogue. The resolver picks the
first id that is actually present in the workspace’s
/serving-endpoints listing.
When unset, resolution is driven by the live Foundation Model API
quality / speed / cost scores: endpoints are classified into
chat classes (classifyEndpoints) and walked best-first
(ChatThinking -> ChatBalanced -> ChatFast), with the small built-in
FALLBACK_MODEL_IDS list as the floor when the catalogue can’t be
read. Set this to
pin a regulated workspace to an approved subset, or to put custom
endpoints in front of the auto-classified catalogue.
feedback?
Section titled “feedback?”
optionalfeedback?:boolean
Log user feedback (thumbs up/down + freeform comments) to MLflow as trace assessments, and surface the feedback controls in the chat UI.
undefined(default, auto): enabled only when MLflow tracing is wired - an OTLP exporter endpoint is set and an MLflow experiment is named (the same signals the observability pipeline needs to ship traces to MLflow). Otherwise off, since there’d be no trace to attach feedback to.true: force on. Feedback controls show and writes are attempted regardless of env detection (use when the env is configured in a way the auto-probe doesn’t recognize).false: force off. No trace-id header, no feedback route, no UI.
Feedback attaches to a turn’s MLflow trace via the OpenTelemetry
trace id the server stamps on each response; see mlflow.ts.
genieIdentity?
Section titled “genieIdentity?”
optionalgenieIdentity?:IdentityMode
Which Databricks identity the agents’ workspace calls run as: the
serving-endpoint catalogue behind the model picker, Genie suggestions,
ask_genie, and the Statement Execution fetch behind a [data:<id>]
embed. Falls back to MASTRA_GENIE_IDENTITY, then "user".
On-behalf-of (OBO) auth requires the caller to be a member of the
WORKSPACE, not just of the Databricks account. An app shared with an
account-level group can be opened by someone whose token is valid but whose
every workspace call fails with Unauthorized access to Org: <id> - and
granting workspace membership is not always possible, since a workspace
caps membership well below the size of a large account’s user group. The
app’s service principal already holds the grants the app was deployed with.
"user"(default): always OBO. Per-user attribution, and Genie / Unity Catalog row filters apply per user. Correct when every caller is a workspace member."service-principal": always the app service principal. Needs no OBO scopes and works for any caller who can open the app, at the cost of per-user attribution in Genie / Unity Catalog."auto": OBO when the request carries an OBO token, the service principal when it does not. For an app serving BOTH the platform front door and a door that has no token to forward - a@dbx-tools/tunnelgate, a Teams channel - where AppKit’sasUserwould otherwise throwAuthenticationErroroutsideNODE_ENV=development.
The service-principal path changes only the Databricks CREDENTIAL. Memory threads, the per-user cache namespace, and trace metadata still key off the forwarded user, so callers sharing the service principal’s data access keep separate conversations and cannot read each other’s threads or charts.
Examples
Section titled “Examples”An app any account user can open
mastra({ genieIdentity: "service-principal", genieSpaces: { default: spaceId } });One app behind both the front door and a public tunnel
mastra({ genieIdentity: "auto", genieSpaces: { default: spaceId } });genieSpaceCacheTtlMs?
Section titled “genieSpaceCacheTtlMs?”
optionalgenieSpaceCacheTtlMs?:number
TTL for the in-memory Genie space metadata cache, in
milliseconds. Defaults to 5 minutes. The Genie agent calls
client.genie.getSpace(...) on every cold-start to get the
title / description / warehouse id; cached responses skip the
round-trip and concurrent callers coalesce on a single
in-flight fetch. Drop to a smaller value when analysts are
actively editing space metadata and you want changes visible
within seconds; raise it to amortise the round-trip when
space metadata is effectively frozen.
Backed by AppKit’s CacheManager, so the cache participates
in telemetry spans (cache.getOrExecute) and benefits from
Lakebase persistence when the lakebase plugin is wired up.
genieSpaces?
Section titled “genieSpaces?”
optionalgenieSpaces?:GenieSpacesConfig
Genie spaces this plugin’s agents can delegate to. One Mastra
tool is registered per alias (genie for the well-known
default alias, genie_<alias> otherwise). Each tool spins
up a per-question Genie sub-agent that runs Databricks
“agent mode” against the space, broadcasts wire events to the
UI, fetches statement rows for non-empty results, and returns
a (string | data | chart)[] summary the host UI renders
inline.
Entries accept either a full GenieSpaceConfig object
or a bare space_id string when no extras are needed:
mastra({ genieSpaces: { default: "01ef0d3c0e1b1f4a8d2c3e4f5a6b7c8d", forecasts: { spaceId: "01ef...", hint: "weekly demand forecasts" }, },});Reach the spaces from an agent’s tools(plugins) callback via
plugins.genie?.toolkit(); the resulting tools accept
{ content, conversationId? } and return a hydrated summary.
Fallback discovery (highest precedence first): if this
field is omitted, the Genie agent also picks up spaces from
(1) the AppKit genie({ spaces: { ... } }) plugin instance
when registered, and (2) the DATABRICKS_GENIE_SPACE_ID
env var (registered under the default alias). This keeps
existing AppKit deployments working without restating the
spaces config in two places.
optionalhost?:string
Inherited from
Section titled “Inherited from”BasePluginConfig.host
optionalmcp?:boolean|MastraMcpConfig
Expose the plugin’s agents (and optionally tools) as a Mastra MCP server so external MCP clients - Claude Desktop, Cursor, the Mastra playground, or another agent - can call them over the standard MCP transports. Enabled by default (agents only): wrapping the already-registered agents costs nothing extra, so the endpoint is on out of the box; only the ambient tools (which assume an in-process chat turn) stay off unless explicitly opted in.
undefined(default) /true: expose every registered agent as anask_<agentId>MCP tool under a server whose id is the plugin name.false: no MCP endpoints.- MastraMcpConfig: fine-grained control over the server id, advertised metadata, and which agents / tools are exposed.
When enabled, the stock Mastra MCP routes mount under the plugin’s
base path (no bespoke route is added - the server is handed to the
Mastra instance via mcpServers, which @mastra/express serves):
- Streamable HTTP:
POST /api/<plugin>/mcp/<serverId>/mcp - SSE (legacy):
GET /api/<plugin>/mcp/<serverId>/ssePOST /api/<plugin>/mcp/<serverId>/messages
Requests run under the same AppKit OBO scope as the chat routes, so an agent invoked over MCP resolves its model and tools as the calling user.
memory?
Section titled “memory?”
optionalmemory?:boolean|MastraMemoryConfig
PgVector store for Mastra memory recall. true reuses the
lakebase plugin’s pool; an object opens a dedicated store.
modelCacheTtlMs?
Section titled “modelCacheTtlMs?”
optionalmodelCacheTtlMs?:number
TTL for the in-memory serving-endpoints list cache, in milliseconds. Defaults to 5 minutes; no env fallback.
The cache is per workspace host and shared across users; concurrent callers coalesce on a single in-flight fetch.
modelFuzzyMatch?
Section titled “modelFuzzyMatch?”
optionalmodelFuzzyMatch?:boolean
Fuzzy-match loose model names ("claude sonnet") against the workspace’s
Model Serving endpoints. Defaults to true; no env fallback.
Set false to require exact endpoint names everywhere.
modelFuzzyThreshold?
Section titled “modelFuzzyThreshold?”
optionalmodelFuzzyThreshold?:number
Fuse.js score threshold for the fuzzy matcher, 0 (exact) to 1 (anything).
Defaults to 0.4; no env fallback.
Lower values reject loose matches; raise it if you have a sprawling endpoint catalogue with similar-looking names.
modelOverride?
Section titled “modelOverride?”
optionalmodelOverride?:boolean
Let clients pick the backing endpoint per request. Defaults to true;
no env fallback.
Reads the X-Mastra-Model header, the ?model= query string, or a
model body field, in that order. Disable when running multi-tenant
where untrusted clients shouldn’t choose the endpoint.
optionalname?:string
Inherited from
Section titled “Inherited from”BasePluginConfig.name
observability?
Section titled “observability?”
optionalobservability?:boolean
Wire Mastra spans into AppKit’s global OTel pipeline via
@mastra/otel-bridge.
undefined(default, auto): on only whenOTEL_EXPORTER_OTLP_ENDPOINTorOTEL_EXPORTER_OTLP_TRACES_ENDPOINTis set. When unset, the bridge is skipped so Mastra does not log[OtelBridge] No OTEL span foundon the noop tracer.true: force on even without an OTLP endpoint.false: force off.
providerId?
Section titled “providerId?”
optionalproviderId?:string
Mastra OpenAI-compatible provider id. Defaults to "databricks"; no env fallback.
remoteSkills?
Section titled “remoteSkills?”
optionalremoteSkills?:RemoteSkillsOption
Remote Agent-Skill sources materialized once at app startup. A single
source, a list, or a { sources, failOnError?, ... } bag.
Each source is a GitHub owner/repo, a git / GitLab URL, or a direct
SKILL.md / archive download URL. Resolution prefers the OPTIONAL skills
npm CLI (a peer dep) which is copied into a temp dir and then persisted;
without it, a URL source is fetched directly. A source that resolves
through neither fails startup unless failOnError: false.
Provisioned skills are written to the Databricks user’s Assistant skills
folder (/Users/<email>/.assistant/skills, the “save this as a skill”
target) so they persist and are picked up by the built-in Assistant-skills
mount. With no writable workspace, they go to a local temp dir instead.
Example
Section titled “Example”mastra({ remoteSkills: "vercel-labs/agent-skills" });mastra({ remoteSkills: { sources: ["vercel-labs/agent-skills", "https://example.com/skill.md"], failOnError: false, },});storage?
Section titled “storage?”
optionalstorage?:boolean|PostgresStoreConfig
PostgresStore for Mastra threads/messages. true reuses the
lakebase plugin’s pool; an object opens a dedicated store.
stripStaleCharts?
Section titled “stripStaleCharts?”
optionalstripStaleCharts?:boolean
When true (default), every agent gets a built-in input
processor that strips chartId fields from prior assistant
tool-invocation results before they reach the model. This
prevents the model from reusing turn-scoped chartIds it sees
in memory recall (which would leave [chart:<id>] markers
pointing at writer events that no longer exist).
Set to false to opt out - useful if a non-default agent
needs full visibility into prior chartIds (e.g. an audit
agent reasoning about chart lineage).
styleInstructions?
Section titled “styleInstructions?”
optionalstyleInstructions?:string|false
Style guardrails appended to every agent’s instructions to curb
common LLM-isms (em dashes, emojis, sycophantic openers, throwaway
closers, excessive hedging).
undefined(default): use the built-inDEFAULT_STYLE_INSTRUCTIONSfromagents.ts.string: replace the default with the supplied block.false: disable entirely (agents see only their bespokeinstructions).
Appended (not prepended) so the agent’s role and rules come first and the style block leans on the model’s recency bias.
telemetry?
Section titled “telemetry?”
optionaltelemetry?:TelemetryOptions
Inherited from
Section titled “Inherited from”BasePluginConfig.telemetry
tools?
Section titled “tools?”
optionaltools?:ToolsInput
Ambient tools spread into every registered agent’s tools record;
per-agent tools win on key collision. Use for a small shared
library; for per-agent tools set agents[id].tools instead.