@dbx-tools/appkit-mastra 0.9.95 → 0.9.105

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,43 +3,35 @@
3
3
  AppKit plugin and server-side toolkit for hosting Mastra agents inside a
4
4
  Databricks App.
5
5
 
6
- Import this package when an AppKit backend needs an agent service with
7
- Databricks on-behalf-of auth, optional Lakebase-backed memory, Databricks Genie
8
- tools, model selection, chart/data embeds, MLflow feedback, and MCP exposure.
9
- The package mounts the standard Mastra agent stream under the AppKit server, so
10
- clients can use Mastra-compatible chat transports instead of a custom protocol.
11
-
12
- Key features:
13
-
14
- - AppKit plugin lifecycle integration: routes, setup, shutdown, sibling plugin
15
- access, and AppKit request context are handled inside `mastra()`.
16
- - Agent composition: define one or more Mastra agents, give each one local tools,
17
- AppKit plugin toolkits, workspace skills, model defaults, and approval-gated
18
- tools.
19
- - Databricks execution model: tool calls run with the active AppKit OBO client
20
- where available, while storage and background work use service-principal
21
- connections. Set `genieIdentity: "service-principal"` to run the agents'
22
- Databricks calls as the app service principal instead, so callers who can open
23
- the app but are not workspace members can still chat, or `"auto"` to make that
24
- fallback per-request - OBO when the caller forwards a token, service principal
25
- when they cannot.
26
- - Durable conversations: Lakebase-backed Mastra storage provides thread
27
- history, message persistence, and optional vector memory.
28
- - Isolated command execution: auto-created workspaces use Databricks Sandbox by
29
- default, created lazily per attributed user outside the App container.
30
- - Rich data answers: Genie tools, statement fetches, chart preparation, and
31
- embed markers let an agent answer with text plus delayed chart/table payloads.
32
- - Operational surfaces: model-list routes, feedback routes, MCP exposure,
33
- scoped API gating, tracing, and MLflow feedback are bundled with the plugin.
34
-
35
- ## Why Not Just AppKit Agents?
36
-
37
- Native AppKit includes a beta Agents plugin with markdown and TypeScript agent
38
- definitions, AppKit tool-provider integration, streaming chat, thread
39
- management, cancellation, and HITL approval. Use it when you want the AppKit
40
- agent model and do not need a separate agent framework.
41
-
42
- Use this package when you specifically want Mastra inside AppKit:
6
+ The plugin mounts Mastra's streaming routes in an AppKit server and adds
7
+ Databricks authentication, Lakebase-backed memory, Genie tools, model selection,
8
+ chart and table embeds, MLflow feedback, and MCP exposure.
9
+
10
+ ## Quick Start
11
+
12
+ Add an agent and run its command tools in a per-user Databricks Sandbox:
13
+
14
+ ```ts
15
+ import { createApp, server } from "@databricks/appkit";
16
+ import { agents, mastra } from "@dbx-tools/appkit-mastra";
17
+
18
+ const analyst = agents.createAgent({
19
+ instructions: "Answer questions and use Python when analysis requires it.",
20
+ });
21
+
22
+ await createApp({
23
+ plugins: [server(), mastra({ agents: { analyst }, sandbox: "databricks" })],
24
+ });
25
+ ```
26
+
27
+ Add Lakebase, Genie, Analytics, or other AppKit plugins when the agent needs
28
+ durable threads or workspace tools.
29
+
30
+ ## Choose Mastra Or AppKit Agents
31
+
32
+ Native AppKit Agents is the shorter path for AppKit-native agent definitions,
33
+ streaming chat, threads, cancellation, and approvals. Choose this package when
34
+ the application already uses Mastra or needs Mastra-specific capabilities:
43
35
 
44
36
  - Mastra's larger plugin/tool ecosystem, MCP support, memory/storage model,
45
37
  workflow primitives, and `@mastra/client-js` stream shape.
@@ -53,7 +45,7 @@ Use this package when you specifically want Mastra inside AppKit:
53
45
  [`@dbx-tools/model`](../model), instead of binding every agent to a fixed
54
46
  endpoint name.
55
47
 
56
- ## Quick Start
48
+ ## Full App Example
57
49
 
58
50
  ```ts
59
51
  import { analytics, createApp, lakebase, server } from "@databricks/appkit";
@@ -96,11 +88,11 @@ await createApp({
96
88
  });
97
89
  ```
98
90
 
99
- Benefits of importing the package:
91
+ This example provides:
100
92
 
101
93
  - `mastra()` registers a full AppKit plugin named `mastra`.
102
94
  - `agents.createAgent()` keeps agent definitions typed and applies the default
103
- Databricks workspace/skill mounts and Databricks Sandbox command execution.
95
+ Databricks workspace skill paths and Monty command execution.
104
96
  - `agents.tool()` lets the same AppKit-shaped tool body work in this Mastra
105
97
  plugin.
106
98
  - `genie.GENIE_INSTRUCTIONS` and `plugins.genie.toolkit()` give agents a
@@ -141,6 +133,10 @@ const approveRefund = agents.createTool({
141
133
  });
142
134
  ```
143
135
 
136
+ Agents are also told to issue independent tool calls together in one turn and
137
+ to keep dependent or conflicting calls sequential. Models that do not support
138
+ parallel tool calls continue through the normal multi-step agent loop.
139
+
144
140
  ## Typed Application Request Context
145
141
 
146
142
  Use Mastra's native `requestContextSchema` for UI selections that should shape a
@@ -269,147 +265,171 @@ and memory configs.
269
265
  ## Workspace Skills
270
266
 
271
267
  Every `agents.createAgent()` gets a default Mastra `Workspace` from
272
- `workspaces.createWorkspace()`. It mounts Databricks Workspace files through the
273
- current OBO user's `WorkspaceClient`, so Mastra can discover Assistant-style
274
- `SKILL.md` files at request time.
275
-
276
- Mastra's native `WorkspaceSkills` owns discovery, indexing, refreshes, and lazy
277
- reads of references, scripts, templates, and assets. dbx-tools does not keep a
278
- second skill catalogue or skill-specific cache.
279
-
280
- When the app registers `filesCache()` from `@dbx-tools/appkit/files-cache`,
281
- auto-created workspaces retain one filesystem source per user and set of actual
282
- mount paths. Page refreshes and later turns reuse that source, allowing Mastra
283
- to retain its native parsed catalogue while the files cache handles repeated
284
- filesystem metadata operations. Each operation resolves the active request's
285
- OBO client, so the retained source does not retain an old token. Explicit
286
- caller-owned workspaces remain unchanged.
287
-
288
- Mastra exposes its native skill search and loading tools. Save or update a
289
- skill with the native workspace file tools by writing
290
- `<skill-root>/<name>/SKILL.md`. Set `workspaceSkills: false` to disable the
291
- skill search processor, or pass `{ topK, minScore, ttlMs }` to tune it.
292
-
293
- Workspace access policy stays on Mastra's native `Workspace.tools` owner. By
294
- default, mounted files are readable without approval. Write, edit, AST edit,
295
- delete, and mkdir run without approval only inside
296
- `/Workspace/Users/<email>` for the authenticated user. Mutations under
297
- organization mounts, `/tmp`, or any other path require approval.
298
- `workspaceTools` accepts Mastra's complete `WorkspaceToolsConfig`, so global or
299
- per-tool settings can change approval, enablement, read-before-write, hooks,
300
- and output limits:
268
+ `workspaces.databricksWorkspace()`. Most apps do not need workspace
269
+ configuration: the default scans `/Workspace/.assistant/skills` and the current
270
+ user's `~/.assistant/skills` path for `SKILL.md` files.
271
+
272
+ Pass paths directly when an agent needs a different filesystem scope:
273
+
274
+ ```ts
275
+ const analyst = agents.createAgent({
276
+ instructions: "Use the project files and skills when relevant.",
277
+ workspace: workspaces.databricksWorkspace({
278
+ assistantPaths: false,
279
+ paths: ["~/project"],
280
+ }),
281
+ });
282
+ ```
283
+
284
+ Paths mount at the same absolute path that they identify. `~` resolves to the
285
+ current user's Databricks workspace home, so `~/project` exposes only that
286
+ subtree. A path that is missing or inaccessible for the current request is
287
+ skipped. Production Databricks mounts require a forwarded token with
288
+ `workspace`, `workspace.workspace`, or `all-apis` scope.
289
+
290
+ Use an options object only when a path needs additional behavior:
291
+
292
+ ```ts
293
+ const workspace = workspaces.databricksWorkspace({
294
+ assistantPaths: false,
295
+ paths: [
296
+ {
297
+ path: "/Workspace/Shared/runbooks",
298
+ skills: ["skills"],
299
+ writable: true,
300
+ createRoot: false,
301
+ },
302
+ {
303
+ path: "/Workspace/Shared/templates",
304
+ readable: false,
305
+ },
306
+ ({ requestContext }) =>
307
+ requestContext.get("team") === "platform" ? "~/platform" : false,
308
+ ],
309
+ });
310
+ ```
311
+
312
+ `readable: false` keeps a mount available to file tools without scanning it for
313
+ skills. `skills` contains relative roots within that path. `writable` controls
314
+ whether the filesystem attempts mutations; Databricks permissions still decide
315
+ whether an operation succeeds. `mount` can expose the path at a different
316
+ Mastra path when required.
317
+
318
+ `/tmp` is opt-in. An explicit `/tmp` path maps to a stable user-scoped directory
319
+ under the host operating system's ephemeral temp location. `/tmp/project` maps
320
+ to a child directory and exposes only `/tmp/project`, not the rest of `/tmp`.
321
+ The location can survive process restarts while the host retains its temp
322
+ storage, but it is not durable storage.
323
+
324
+ The shortcut returns a native Mastra workspace and accepts native `mounts`,
325
+ `tools`, and workspace options. Use the config helper when composing the result
326
+ with another Mastra provider:
327
+
328
+ ```ts
329
+ import { Workspace } from "@mastra/core/workspace";
330
+
331
+ export const workspace = new Workspace({
332
+ ...workspaces.databricksWorkspaceConfig({
333
+ assistantPaths: false,
334
+ paths: ["~/project", "/tmp/project"],
335
+ }),
336
+ sandbox: mySandbox,
337
+ });
338
+ ```
339
+
340
+ Mastra discovers and loads skills from the configured roots. Set
341
+ `workspaceSkills: false` to disable skill search, or pass `{ topK, minScore,
342
+ ttlMs }` to tune it.
343
+
344
+ ### Cache Workspace Metadata
345
+
346
+ Register `filesCache()` to reuse Databricks directory metadata across page
347
+ refreshes and later turns:
348
+
349
+ ```ts
350
+ import { filesCache } from "@dbx-tools/appkit/files-cache";
351
+
352
+ await createApp({
353
+ plugins: [server(), filesCache(), mastra({ agents: { analyst } })],
354
+ });
355
+ ```
356
+
357
+ The cache is isolated by user and mount path. It stores `exists`, `readdir`, and
358
+ `stat` results for mounted Databricks paths and caches `readFile` only under
359
+ skill roots. Set `cache: false` to disable it or provide filters:
360
+
361
+ ```ts
362
+ const workspace = workspaces.databricksWorkspace({
363
+ paths: ["~/project"],
364
+ cache: [
365
+ { operations: ["exists", "readdir", "stat"], paths: "**" },
366
+ { operations: "readFile", paths: "~/project/skills/**" },
367
+ ],
368
+ });
369
+ ```
370
+
371
+ ### Configure File Approvals
372
+
373
+ Workspace tools are enabled and run without approval by default. This applies to
374
+ file mutations and command execution with either Monty or Databricks Sandbox.
375
+ Databricks permissions still decide whether a workspace file operation
376
+ succeeds. Opt into approval for the tools that need it:
301
377
 
302
378
  ```ts
303
379
  import { WORKSPACE_TOOLS } from "@mastra/core/workspace";
304
380
 
305
- mastra({
306
- workspaceTools: {
307
- requireApproval: false,
381
+ const workspace = workspaces.databricksWorkspace({
382
+ paths: ["~/project"],
383
+ tools: {
308
384
  [WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE]: {
309
385
  requireApproval: true,
310
386
  requireReadBeforeWrite: true,
311
387
  },
388
+ [WORKSPACE_TOOLS.FILESYSTEM.DELETE]: {
389
+ requireApproval: true,
390
+ },
312
391
  },
313
392
  });
314
393
  ```
315
394
 
316
- File-tool and sandbox-command policies are independent. Disable
317
- `WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND` when an agent must not bypass file
318
- approvals by writing through shell commands.
319
-
320
- Locations are a named map (`skillFolders`), so an app refers to a tree by name
321
- rather than repeating a path. Databricks paths mount at their actual workspace
322
- location and carry relative `skills` roots plus their own policy: `readable`
323
- (scanned for `SKILL.md`, default `true`) and `writable` (default `true` for
324
- `/Workspace` roots, `false` elsewhere).
325
- `DEFAULT_SKILL_FOLDERS` supplies these:
326
-
327
- | Name | Mount | Skill root | Readable | Writable |
328
- | --------------------- | ------------------------------------ | ------------------- | -------- | -------- |
329
- | `organization-skills` | `/Workspace/.assistant` | `skills` | yes | yes |
330
- | `personal-skills` | `/Workspace/Users/<email>` | `.assistant/skills` | yes | yes |
331
-
332
- Every workspace also has an isolated local scratch filesystem mounted at
333
- `/tmp`. Organization and personal mounts are probed independently on first
334
- load. A missing or inaccessible Databricks path is skipped, so `/tmp` and any
335
- accessible mounts remain available.
336
-
337
- Organization writes are enabled at the filesystem layer, require approval, and
338
- still depend on the caller's Databricks permissions. The existing
339
- `/Workspace/.assistant` root is never created automatically.
340
-
341
- Skill roots are expanded to concrete skill directories before Mastra scans
342
- them. The first root wins duplicate directory names, so organization skills
343
- override same-named personal skills while unique personal skills remain
344
- available.
345
-
346
- A consuming library merges over that map: a matching name overrides the
347
- default, `false` disables it, and any other name adds a location. A folder
348
- points at a Databricks `path` (a literal, or a function resolving one per
349
- request) or supplies a ready `filesystem` for anything the OBO client cannot
350
- reach.
395
+ Set `enabled: false` on a tool to remove it. File approvals and sandbox commands
396
+ are separate, so gate or disable
397
+ `WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND` when commands must not bypass file
398
+ policies. Cached metadata never grants Databricks access.
399
+
400
+ ## Workspace Sandbox
401
+
402
+ Run command tools in a per-user Beta
403
+ [Databricks Sandbox](https://docs.databricks.com/aws/en/compute/serverless/sandbox):
351
404
 
352
405
  ```ts
353
- const agent = agents.createAgent({
354
- instructions: "Use mounted workspace skills when relevant.",
355
- workspace: workspaces.createWorkspace({
356
- skillFolders: {
357
- // Point an existing name somewhere else.
358
- "organization-skills": {
359
- path: "/Workspace/Shared/.assistant",
360
- skills: ["skills"],
361
- },
362
- // Drop a default entirely.
363
- "personal-skills": false,
364
- // Add an app-owned tree the agent may write back to.
365
- runbooks: {
366
- path: "/Workspace/Shared/runbooks",
367
- skills: ["skills"],
368
- writable: true,
369
- },
370
- // Mount for file tools without adding it to skill discovery.
371
- templates: { path: "/Workspace/Shared/templates", readable: false },
372
- // Any Mastra filesystem works, including per-request ones.
373
- volume: { filesystem: ({ requestContext }) => volumeFor(requestContext) },
374
- },
375
- mounts: [
376
- async () => ({
377
- mounts: { "/reference": myFilesystem },
378
- skillPaths: ["/reference/skills"],
379
- }),
380
- ],
381
- }),
406
+ mastra({
407
+ agents: { analyst },
408
+ sandbox: "databricks",
382
409
  });
383
410
  ```
384
411
 
385
- A folder whose location resolves to `undefined` is skipped for that request,
386
- which is how `personal-skills` drops out when no user email is stamped.
387
- `assistantSkills: false` starts from an empty map, leaving only the
388
- `skillFolders` given. Production workspace mounts require a forwarded token
389
- with `workspace`, `workspace.workspace`, or `all-apis` scope. Development mode
390
- skips that gate for local iteration.
412
+ Use `sandbox: true` for the same selection. Pass options to set startup and
413
+ command limits or to fall back to the local Python runtime when the workspace
414
+ does not have the preview:
391
415
 
392
- ## Workspace Sandbox
416
+ ```ts
417
+ mastra({
418
+ agents: { analyst },
419
+ sandbox: {
420
+ inactivityTimeout: "1800s",
421
+ startupTimeoutMs: 180_000,
422
+ commandTimeoutMs: 60_000,
423
+ fallback: "monty",
424
+ },
425
+ });
426
+ ```
393
427
 
394
- Auto-created agent workspaces use the Node `@pydantic/monty` runtime by default,
395
- so Python command tools work without a workspace preview or remote API.
396
- Monty's native subprocess worker is preferred because Bun's Linux
397
- `worker_threads` support cannot reliably host the WASM worker. The WASM entry is
398
- loaded only when native import fails. Databricks App staging declares the Linux
399
- native package directly so deployment does not depend on transitive optional
400
- dependency installation.
401
-
402
- Opt into the Beta
403
- [Databricks Sandbox](https://docs.databricks.com/aws/en/compute/serverless/sandbox)
404
- with `sandbox: true`, `sandbox: "databricks"`, or a Databricks options object.
405
- The provider derives a stable opaque sandbox id from the workspace and
406
- attributed user, creates the sandbox lazily on the first command, starts a
407
- stopped sandbox, and waits for runnable state. Commands execute through the
408
- synchronous Sandbox API and return Mastra's normal stdout, stderr, exit,
409
- timeout, and truncation fields. When the Beta is definitively unavailable, its
410
- configured fallback defaults to Monty. Permission, authentication, and
411
- transient network failures remain visible instead of silently changing
412
- providers.
428
+ The sandbox is created on the first command and reused for the attributed user.
429
+ Commands return the normal Mastra stdout, stderr, exit, timeout, and truncation
430
+ fields. Authentication, permission, and network failures are returned to the
431
+ caller; only a definitive unavailable-preview response uses the configured
432
+ fallback.
413
433
 
414
434
  Enable Databricks Sandbox in the workspace Previews page before selecting it.
415
435
  The adapter creates its own AppKit client through the normal
@@ -420,14 +440,7 @@ explicit OBO client must request the Sandbox API's `sandbox` scope. The Sandbox
420
440
  filesystem is separate from Databricks Workspace skill mounts; command code must
421
441
  copy data explicitly when it needs both.
422
442
 
423
- Monty is intentionally narrower than Databricks Sandbox: it accepts Python
424
- source directly (or `python3 -c`), runs in crash-isolated subprocess workers,
425
- and exposes no host shell, filesystem, network, environment variables, or
426
- third-party packages. Per-command cancellation kills the isolated worker, and
427
- `maxRetainedBytes` bounds retained stdout/stderr without dropping callback
428
- chunks. Prefer Python source for commands that must work on both providers.
429
-
430
- The default needs no configuration:
443
+ Without a `sandbox` option, command tools use the local Monty Python runtime:
431
444
 
432
445
  ```ts
433
446
  mastra({
@@ -435,19 +448,9 @@ mastra({
435
448
  });
436
449
  ```
437
450
 
438
- Tune the Databricks lifecycle globally for auto-created workspaces:
439
-
440
- ```ts
441
- mastra({
442
- agents: analyst,
443
- sandbox: {
444
- inactivityTimeout: "1800s",
445
- startupTimeoutMs: 180_000,
446
- commandTimeoutMs: 60_000,
447
- fallback: "monty",
448
- },
449
- });
450
- ```
451
+ Monty accepts Python source or `python3 -c` and has no host filesystem, network,
452
+ environment variables, shell, or third-party packages. Use Python source when a
453
+ command must work with either provider.
451
454
 
452
455
  Disable command execution, select Databricks, or provide any Mastra sandbox on
453
456
  one agent:
@@ -458,25 +461,20 @@ mastra({ agents: analyst, sandbox: "databricks" });
458
461
 
459
462
  const localAgent = agents.createAgent({
460
463
  instructions: "Run only trusted local commands.",
461
- workspace: workspaces.createWorkspace({
464
+ workspace: workspaces.databricksWorkspace({
462
465
  sandbox: myMastraSandbox,
463
466
  }),
464
467
  });
465
468
  ```
466
469
 
467
- An explicit agent `workspace` always wins over plugin-level `sandbox` config, so
468
- providers never run in parallel accidentally. `workspaces.createWorkspace()`
469
- also accepts a custom resolver for per-request provider selection. A per-agent
470
- workspace resolver returning `undefined` explicitly disables the workspace for
471
- that agent.
470
+ An agent-level workspace overrides the plugin-level sandbox setting. Returning
471
+ `undefined` from a workspace resolver disables the workspace for that agent.
472
472
 
473
473
  ## Remote Skills
474
474
 
475
- Workspace skills above are discovered from files ALREADY in the Databricks
476
- workspace. `remoteSkills` provisions skills from OUTSIDE it at startup - a
477
- GitHub `owner/repo`, a git / GitLab URL, or a direct `SKILL.md` / archive
478
- download URL - so an app can ship with a curated skill set without anyone
479
- hand-uploading `SKILL.md` trees first.
475
+ Use `remoteSkills` to install a curated skill set when the files are not already
476
+ in the Databricks workspace. Sources can be a GitHub `owner/repo`, a git URL, a
477
+ direct `SKILL.md`, or an archive URL.
480
478
 
481
479
  ```ts
482
480
  mastra({
@@ -488,54 +486,29 @@ mastra({
488
486
  });
489
487
  ```
490
488
 
491
- Each source is materialized at boot into an Assistant-style `SKILL.md` tree that
492
- the default workspace then scans, so a provisioned skill behaves exactly like
493
- one that was in the workspace all along. Resolution per source:
494
-
495
- - if the optional `skills` peer dependency is installed, the source is copied
496
- into a staging dir with the `skills` CLI, which understands every source
497
- format the ecosystem does (GitHub shorthand, git URLs, archive URLs);
498
- - otherwise the source URL is fetched directly and its `SKILL.md` written to the
499
- staging dir. A non-URL source (e.g. bare `owner/repo`) without the `skills`
500
- package installed cannot be resolved this way and fails.
501
-
502
- The default destination is the Databricks organization skills tree
503
- (`/Workspace/.assistant/skills`), so provisioned skills persist across restarts and are picked up by
504
- the built-in Assistant-skills mount. Pass `userEmail` to target that user's
505
- `/Workspace/Users/<email>/.assistant/skills` instead, or `databricksBasePath` for an
506
- explicit tree. When no Databricks client is resolvable at startup, the tree is
507
- written to a local temp dir and handed to Mastra as an extra local skill path
508
- for the current process only.
509
-
510
- The destination is **probed with a real write** before it is used, and falls back
511
- to that local tree when the probe fails. Writing the shared
512
- `/Workspace/.assistant/skills` tree is a workspace-ADMIN action, and a Databricks
513
- App runs as a non-admin service principal, so the common deployment cannot write
514
- it - and the workspace API reports a path the caller may not touch as
515
- `RESOURCE_DOES_NOT_EXIST` rather than a permission error. Only the storage
516
- LOCATION degrades: the same skills are provisioned either way, so a
517
- non-admin app keeps a working agent instead of failing startup. Give the app's
518
- service principal `CAN_MANAGE` on the tree (or point `databricksBasePath` at one
519
- it owns) to get workspace persistence back.
520
-
521
- A source that resolves through neither path fails app startup, so a misconfigured
522
- skill set is caught at boot rather than silently missing. Set `failOnError: false`
523
- (top-level or per-source) to log and skip a bad source instead. Install the
524
- optional peer to enable the richest source formats:
489
+ Each source is copied into an Assistant-style `SKILL.md` tree at startup. Install
490
+ the optional `skills` package for GitHub shorthand, git repositories, and archive
491
+ URLs:
525
492
 
526
493
  ```sh
527
- pnpm add skills
494
+ bun add skills
528
495
  ```
529
496
 
497
+ Without that package, direct `SKILL.md` URLs still work.
498
+
499
+ The default destination is `/Workspace/.assistant/skills`. Set `userEmail` for a
500
+ user-specific Assistant tree or `databricksBasePath` for another location. If
501
+ the app cannot write the selected workspace path, it uses a process-local skill
502
+ tree so the agent can still start. Grant the app service principal access to the
503
+ workspace path when the skills must persist across restarts.
504
+
505
+ A source error fails startup by default. Set `failOnError: false` globally or on
506
+ one source to log and skip it.
507
+
530
508
  ### Refresh policy
531
509
 
532
- Provisioning runs on every app boot, and skill trees change rarely, so each
533
- provisioned tree carries a `.metadata.json` at its root recording when each
534
- source was last downloaded. A source is only re-downloaded once that record is
535
- older than seven days; inside the window the existing tree is reused and no network
536
- call is made. The record travels with the tree rather than living in process
537
- memory, so a container that restarts a dozen times an hour pulls each source
538
- once, not a dozen times.
510
+ Downloaded sources are reused for seven days by default. Set `refreshTtlMs` to a
511
+ shorter interval or `0` to download on every boot:
539
512
 
540
513
  ```ts
541
514
  mastra({
@@ -551,11 +524,8 @@ mastra({
551
524
  });
552
525
  ```
553
526
 
554
- The record is keyed by the source AND the options that change what it contains
555
- (`skills`, `experimental`, `ref`), so narrowing a skill list or moving a `ref`
556
- re-downloads immediately rather than serving the previous selection for seven days.
557
- A missing or unreadable record is treated as a cache miss, never as a startup
558
- failure.
527
+ Changing a source's `skills`, `experimental`, or `ref` option refreshes it
528
+ immediately.
559
529
 
560
530
  ## Databricks AI Tools
561
531
 
@@ -742,8 +712,10 @@ same in either mode; chrome is not.
742
712
  ## Model Selection
743
713
 
744
714
  `model.buildModel()` adapts the generic resolver from
745
- [`@dbx-tools/model`](../model) to Mastra. It resolves the model per request,
746
- so OBO identity and request-specific overrides stay isolated.
715
+ [`@dbx-tools/model`](../model) to Mastra, then constructs a request-scoped
716
+ Vercel AI SDK ProviderV4 model through
717
+ [`@dbx-tools/model-protocol`](../model-protocol). It resolves the model per
718
+ request, so OBO identity and request-specific overrides stay isolated.
747
719
 
748
720
  Model priority is:
749
721
 
@@ -772,14 +744,16 @@ Use `serving.extractModelOverride()` and `serving.resolveServingConfig()` when
772
744
  building custom routes that should behave like the plugin's `/models` and stream
773
745
  routes.
774
746
 
775
- The serving fetch interceptor repairs provider-specific wire requirements for
776
- both `fetch(url, { body })` and `fetch(new Request(...))`. In particular,
747
+ The Chat provider uses a provider-local fetch from
748
+ `@dbx-tools/model-protocol`; Mastra does not patch `globalThis.fetch`. The
749
+ shared fetch repairs provider-specific wire requirements for both
750
+ `fetch(url, { body })` and `fetch(new Request(...))`. In particular,
777
751
  Databricks-hosted GPT 5.6 Chat Completions with function tools receives
778
752
  `reasoning_effort: "none"` even when a caller default selected another effort.
779
753
  Other Chat models receive no synthesized effort, while an explicit supported
780
754
  caller value is preserved. Responses-only models such as GPT Astra use the
781
755
  native Responses provider. Claude reasoning replay and Gemini/Claude structured
782
- response content continue through the same sanitizer.
756
+ response content continue through the same shared sanitizer.
783
757
 
784
758
  Responses turns set `store: false`. The OpenAI provider automatically includes
785
759
  encrypted reasoning state so a tool continuation sends the complete stateless
@@ -1048,8 +1022,7 @@ needs no extra wiring.
1048
1022
 
1049
1023
  ## Configuration Reference
1050
1024
 
1051
- The plugin config is intentionally centered on the AppKit lifecycle instead of
1052
- requiring callers to assemble a Mastra server by hand.
1025
+ The main plugin options are:
1053
1026
 
1054
1027
  - `agents` registers a single agent, an array, or a record keyed by stable agent
1055
1028
  ids. Records are best for UIs because the ids become route-visible.
@@ -1064,9 +1037,8 @@ requiring callers to assemble a Mastra server by hand.
1064
1037
  Pass `false` to disable it or an object with `topK`, `minScore`, and `ttlMs`
1065
1038
  overrides.
1066
1039
  - `workspaceTools` forwards Mastra's native workspace-tool configuration.
1067
- Reads do not require approval. Filesystem mutations require approval outside
1068
- the authenticated user's `/Workspace/Users/<email>` home. Explicit global or
1069
- per-tool settings override those defaults.
1040
+ All tools are enabled without approval by default. Global and per-tool
1041
+ settings can require approval or disable selected tools.
1070
1042
  - `remoteSkills` provisions `SKILL.md` sources from outside the workspace at
1071
1043
  startup (see [Remote Skills](#remote-skills)). Accepts a single source, a
1072
1044
  list, or an options bag with `failOnError`, `userEmail`,
@@ -1075,9 +1047,8 @@ requiring callers to assemble a Mastra server by hand.
1075
1047
  [Databricks AI Tools](#databricks-ai-tools)) or any URL-like.
1076
1048
  - `genieSpaces` maps aliases to Genie Space IDs (or to
1077
1049
  `{ spaceId, hint }` objects). Those aliases flow into tool names,
1078
- suggestions, and chart/data workflows. An alias present with no space id is a
1079
- wiring contradiction and fails at construction rather than silently
1080
- registering no Genie tools.
1050
+ suggestions, and chart/data workflows. Every configured alias needs a space
1051
+ id.
1081
1052
  - `genieAgentMode` defaults to `true` for the streaming Agent Mode API. Set it
1082
1053
  to `false` to force Conversation API polling. Pre-stream feature-disabled or
1083
1054
  preview-toggle responses fall back automatically.
@@ -1088,33 +1059,18 @@ requiring callers to assemble a Mastra server by hand.
1088
1059
  Explicit `true` fails startup unless an experiment id or name is configured.
1089
1060
  - `mcp` controls whether agents are exposed as MCP tools and how that server is
1090
1061
  named.
1091
- - `genieIdentity` picks the Databricks identity the agents' workspace calls run
1092
- as - the serving catalogue behind the model picker, Genie suggestions,
1093
- `ask_genie`, and the statement fetch behind a `[data:<id>]` embed. `"user"`
1094
- (default) is always on-behalf-of the signed-in user, so callers must be
1095
- members of the WORKSPACE, not just the Databricks account. `"service-principal"`
1096
- runs those calls as the app service principal instead, so any caller who can
1097
- open the app works even without workspace membership - useful when an app is
1098
- shared with an account-level group too large to add to the workspace. It
1099
- changes only the Databricks credential: memory threads, the per-user cache
1100
- namespace, and trace metadata still key off the forwarded user, at the cost
1101
- of per-user attribution in Genie / Unity Catalog. `"auto"` decides PER REQUEST:
1102
- OBO when the request actually carries an OBO token, service principal when it
1103
- does not. That is the mode for an app served through more than one door - a
1104
- container fronted by [`@dbx-tools/tunnel`](../../node/tunnel) serves both
1105
- email-code callers (no Databricks credential exists to forward) and the
1106
- platform front door on one port, and `"user"` would make every tunnel turn fail
1107
- with AppKit's `AuthenticationError` while `"service-principal"` would throw away
1108
- per-user scoping for the front-door callers who still have it. Falls back to
1109
- `MASTRA_GENIE_IDENTITY`. The decision itself lives in
1110
- [`@dbx-tools/appkit`](../appkit)'s `identity` module, so a non-Mastra plugin can
1111
- make the same call.
1062
+ - `genieIdentity` selects credentials for model discovery, Genie calls, and
1063
+ statement fetches. `"user"` uses OBO and requires workspace membership.
1064
+ `"service-principal"` lets account-level users call the app without workspace
1065
+ membership. `"auto"` uses OBO when the request includes it and otherwise uses
1066
+ the service principal. Memory threads, cache namespaces, and trace metadata
1067
+ remain user-scoped in all three modes. The environment fallback is
1068
+ `MASTRA_GENIE_IDENTITY`.
1112
1069
  - `apiAccess` chooses the route allowlist. Keep the default scoped mode for
1113
1070
  deployed apps.
1114
1071
 
1115
- Use this package when you want an AppKit-native agent runtime. Use the shared
1116
- schemas in [`@dbx-tools/shared-mastra`](../../shared/mastra) when building a
1117
- client that talks to these routes.
1072
+ Clients that call these routes can import the browser-safe schemas from
1073
+ [`@dbx-tools/shared-mastra`](../../shared/mastra).
1118
1074
 
1119
1075
  ## Modules
1120
1076
 
@@ -1142,13 +1098,10 @@ client that talks to these routes.
1142
1098
  adapter.
1143
1099
  - `montySandbox` - Python-only Pydantic Monty fallback using Node subprocess
1144
1100
  workers.
1145
- - `workspaces` / `filesystems` - Mastra workspace creation with a default
1146
- Databricks sandbox plus named
1147
- `skillFolders` (defaults `organization-skills` / `personal-skills`, overridable
1148
- by consumers); `filesystems(fs)` wraps any `@dbx-tools/shared-fs`
1149
- `FileSystem` (including `@dbx-tools/databricks` / `@dbx-tools/fs`) as a
1150
- Mastra mount, with `scratchFilesystem` (fresh `tmpFS` + random id) when no
1151
- other mount resolves.
1101
+ - `workspaces` / `filesystems` - native Mastra workspace configuration from
1102
+ Databricks paths, opt-in user-scoped temp paths, and caller-supplied mounts;
1103
+ `filesystems(fs)` wraps any `@dbx-tools/shared-fs` `FileSystem` (including
1104
+ `@dbx-tools/databricks` / `@dbx-tools/fs`) as a Mastra mount.
1152
1105
  - `remote-skills` - startup provisioning of remote `SKILL.md` sources into the
1153
1106
  Databricks Assistant skills tree (or a local temp dir): the `"aitools"`
1154
1107
  constant reads Databricks' own skill repo directly, and any other source goes