@agent-native/core 0.22.45 → 0.24.0

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.
Files changed (138) hide show
  1. package/dist/a2a/artifact-response.js +1 -1
  2. package/dist/a2a/artifact-response.js.map +1 -1
  3. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  4. package/dist/agent/engine/builder-engine.js +5 -6
  5. package/dist/agent/engine/builder-engine.js.map +1 -1
  6. package/dist/agent/production-agent.d.ts.map +1 -1
  7. package/dist/agent/production-agent.js +12 -4
  8. package/dist/agent/production-agent.js.map +1 -1
  9. package/dist/agent/run-manager.d.ts +9 -2
  10. package/dist/agent/run-manager.d.ts.map +1 -1
  11. package/dist/agent/run-manager.js +9 -2
  12. package/dist/agent/run-manager.js.map +1 -1
  13. package/dist/cli/app-skill.d.ts +139 -0
  14. package/dist/cli/app-skill.d.ts.map +1 -0
  15. package/dist/cli/app-skill.js +960 -0
  16. package/dist/cli/app-skill.js.map +1 -0
  17. package/dist/cli/create.d.ts.map +1 -1
  18. package/dist/cli/create.js +13 -4
  19. package/dist/cli/create.js.map +1 -1
  20. package/dist/cli/index.js +24 -0
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/skills.d.ts +39 -0
  23. package/dist/cli/skills.d.ts.map +1 -0
  24. package/dist/cli/skills.js +363 -0
  25. package/dist/cli/skills.js.map +1 -0
  26. package/dist/cli/templates-meta.d.ts.map +1 -1
  27. package/dist/cli/templates-meta.js +9 -6
  28. package/dist/cli/templates-meta.js.map +1 -1
  29. package/dist/cli/workspace-dev.d.ts.map +1 -1
  30. package/dist/cli/workspace-dev.js +103 -9
  31. package/dist/cli/workspace-dev.js.map +1 -1
  32. package/dist/client/AgentPanel.d.ts +2 -0
  33. package/dist/client/AgentPanel.d.ts.map +1 -1
  34. package/dist/client/AgentPanel.js +2 -2
  35. package/dist/client/AgentPanel.js.map +1 -1
  36. package/dist/client/AssistantChat.d.ts +13 -0
  37. package/dist/client/AssistantChat.d.ts.map +1 -1
  38. package/dist/client/AssistantChat.js +66 -22
  39. package/dist/client/AssistantChat.js.map +1 -1
  40. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  41. package/dist/client/MultiTabAssistantChat.js +17 -1
  42. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  43. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  44. package/dist/client/agent-chat-adapter.js +70 -10
  45. package/dist/client/agent-chat-adapter.js.map +1 -1
  46. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  47. package/dist/client/extensions/ExtensionViewer.js +157 -2
  48. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  49. package/dist/client/index.d.ts +1 -1
  50. package/dist/client/index.d.ts.map +1 -1
  51. package/dist/client/index.js.map +1 -1
  52. package/dist/client/sse-event-processor.d.ts +6 -0
  53. package/dist/client/sse-event-processor.d.ts.map +1 -1
  54. package/dist/client/sse-event-processor.js +9 -2
  55. package/dist/client/sse-event-processor.js.map +1 -1
  56. package/dist/client/use-chat-threads.d.ts +8 -1
  57. package/dist/client/use-chat-threads.d.ts.map +1 -1
  58. package/dist/client/use-chat-threads.js +37 -7
  59. package/dist/client/use-chat-threads.js.map +1 -1
  60. package/dist/client/use-chat-threads.spec.js +59 -0
  61. package/dist/client/use-chat-threads.spec.js.map +1 -1
  62. package/dist/deploy/workspace-deploy.js +6 -0
  63. package/dist/deploy/workspace-deploy.js.map +1 -1
  64. package/dist/extensions/actions.d.ts.map +1 -1
  65. package/dist/extensions/actions.js +112 -2
  66. package/dist/extensions/actions.js.map +1 -1
  67. package/dist/extensions/routes.d.ts.map +1 -1
  68. package/dist/extensions/routes.js +37 -2
  69. package/dist/extensions/routes.js.map +1 -1
  70. package/dist/extensions/schema.d.ts +275 -0
  71. package/dist/extensions/schema.d.ts.map +1 -1
  72. package/dist/extensions/schema.js +53 -1
  73. package/dist/extensions/schema.js.map +1 -1
  74. package/dist/extensions/store.d.ts +40 -0
  75. package/dist/extensions/store.d.ts.map +1 -1
  76. package/dist/extensions/store.js +367 -3
  77. package/dist/extensions/store.js.map +1 -1
  78. package/dist/mcp-client/index.d.ts +1 -1
  79. package/dist/mcp-client/index.d.ts.map +1 -1
  80. package/dist/mcp-client/index.js +1 -1
  81. package/dist/mcp-client/index.js.map +1 -1
  82. package/dist/mcp-client/routes.d.ts +1 -0
  83. package/dist/mcp-client/routes.d.ts.map +1 -1
  84. package/dist/mcp-client/routes.js +52 -0
  85. package/dist/mcp-client/routes.js.map +1 -1
  86. package/dist/mcp-client/workspace-servers.d.ts +15 -0
  87. package/dist/mcp-client/workspace-servers.d.ts.map +1 -0
  88. package/dist/mcp-client/workspace-servers.js +297 -0
  89. package/dist/mcp-client/workspace-servers.js.map +1 -0
  90. package/dist/resources/handlers.d.ts.map +1 -1
  91. package/dist/resources/handlers.js +38 -25
  92. package/dist/resources/handlers.js.map +1 -1
  93. package/dist/resources/store.d.ts +11 -3
  94. package/dist/resources/store.d.ts.map +1 -1
  95. package/dist/resources/store.js +220 -9
  96. package/dist/resources/store.js.map +1 -1
  97. package/dist/scripts/call-agent.js +1 -1
  98. package/dist/scripts/call-agent.js.map +1 -1
  99. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  100. package/dist/server/agent-chat-plugin.js +25 -6
  101. package/dist/server/agent-chat-plugin.js.map +1 -1
  102. package/dist/server/agent-discovery.d.ts.map +1 -1
  103. package/dist/server/agent-discovery.js +34 -9
  104. package/dist/server/agent-discovery.js.map +1 -1
  105. package/dist/server/auth-marketing.d.ts.map +1 -1
  106. package/dist/server/auth-marketing.js +8 -5
  107. package/dist/server/auth-marketing.js.map +1 -1
  108. package/dist/server/auth.d.ts.map +1 -1
  109. package/dist/server/auth.js +6 -2
  110. package/dist/server/auth.js.map +1 -1
  111. package/dist/templates/default/AGENTS.md +12 -4
  112. package/dist/templates/default/DEVELOPING.md +7 -5
  113. package/dist/templates/workspace-core/AGENTS.md +7 -0
  114. package/dist/templates/workspace-root/AGENTS.md +6 -0
  115. package/docs/content/creating-templates.md +14 -9
  116. package/docs/content/database.md +44 -17
  117. package/docs/content/deployment.md +15 -7
  118. package/docs/content/dispatch.md +7 -1
  119. package/docs/content/embedding-sdk.md +79 -0
  120. package/docs/content/extensions.md +5 -0
  121. package/docs/content/key-concepts.md +15 -17
  122. package/docs/content/mcp-clients.md +30 -0
  123. package/docs/content/multi-app-workspace.md +3 -2
  124. package/docs/content/multi-tenancy.md +4 -4
  125. package/docs/content/server.md +10 -7
  126. package/docs/content/skills-guide.md +75 -0
  127. package/docs/content/template-analytics.md +1 -1
  128. package/docs/content/template-assets.md +130 -0
  129. package/docs/content/template-dispatch.md +3 -2
  130. package/docs/content/template-slides.md +2 -2
  131. package/docs/content/workspace-management.md +2 -2
  132. package/docs/content/workspace.md +11 -9
  133. package/package.json +1 -1
  134. package/src/templates/default/AGENTS.md +12 -4
  135. package/src/templates/default/DEVELOPING.md +7 -5
  136. package/src/templates/workspace-core/AGENTS.md +7 -0
  137. package/src/templates/workspace-root/AGENTS.md +6 -0
  138. package/docs/content/template-images.md +0 -55
@@ -6,12 +6,19 @@ This is an **@agent-native/core** application -- the AI agent and UI share state
6
6
 
7
7
  ### Core Principles
8
8
 
9
- 1. **Shared SQL database** -- All app state lives in SQL (SQLite locally, cloud DB via `DATABASE_URL` in production). Core stores: `application_state`, `settings`, `oauth_tokens`, `sessions`, `resources`.
9
+ 1. **Shared SQL database** -- All app state lives in SQL. Local SQLite at `data/app.db` is the zero-setup dev fallback; deployed apps need a persistent `DATABASE_URL` so data survives container/serverless restarts. Turso is optional, not required: Neon, Supabase, Turso/libSQL, plain Postgres, durable SQLite, D1 bindings, and Builder.io-managed environments are all valid when supported by the deploy. Core stores: `application_state`, `settings`, `oauth_tokens`, `sessions`, `resources`.
10
10
  2. **All AI through agent chat** -- No inline LLM calls. UI delegates to the AI via `sendToAgentChat()` / `agentChat.submit()`.
11
11
  3. **Actions for agent operations** -- `pnpm action <name>` dispatches to callable action files in `actions/`.
12
12
  4. **Live sync keeps the UI current** -- Database writes stream over `/_agent-native/events` first, with `/_agent-native/poll` as the fallback. **When you (the agent) write data, the UI must reflect the change without a manual refresh.** This is non-negotiable. Use `useActionQuery` / `useActionMutation` for action-backed data (preferred). If you use raw `useQuery`, fold `useChangeVersions([<source>, "action"])` into the key for targeted refreshes. See the `real-time-sync` and `adding-a-feature` skills.
13
13
  5. **Agent can update code** -- The agent can modify this app's source code directly.
14
14
 
15
+ ### Database Code
16
+
17
+ - Define tables with `@agent-native/core/db/schema` helpers (`table`, `text`, `integer`, `real`, `now`, sharing helpers), never `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core`.
18
+ - Use Drizzle's query builder (`db.select`, `db.insert`, `db.update`, `db.delete`) plus portable operators from `drizzle-orm` (`eq`, `and`, `or`, `inArray`, `desc`, etc.) for app reads and writes.
19
+ - Keep raw SQL out of normal actions, handlers, and stores. Use it only for additive migrations, health checks, or last-resort maintenance, and keep it parameterized and dialect-agnostic.
20
+ - Do not write SQLite-only or Postgres-only syntax in product code. The same app should run on SQLite, Postgres, libSQL/Turso, D1, and other supported Drizzle backends.
21
+
15
22
  ### Authentication
16
23
 
17
24
  Auth is automatic and environment-driven:
@@ -77,12 +84,13 @@ You do NOT get auto-injected screen state. **Call `pnpm action view-screen` at t
77
84
  | `hello` | `[--name <name>]` | Example script |
78
85
  | `db-schema` | | Show all tables, columns, types |
79
86
  | `db-query` | `--sql "SELECT ..."` | Run a SELECT query |
80
- | `db-exec` | `--sql "INSERT ..."` | Run INSERT/UPDATE/DELETE (use for short/multi-column writes) |
87
+ | `db-exec` | `--sql "UPDATE ..."` | Last-resort ad-hoc maintenance; prefer domain actions and Drizzle code for product work |
81
88
  | `db-patch` | `--table <t> --column <c> --where "<clause>" --find "<old>" --replace "<new>"` | Surgical search/replace on a large text column — sends a diff instead of the full value |
82
89
 
83
- **Pick the right SQL tool:**
90
+ **For one-off maintenance, pick the right SQL tool:**
84
91
 
85
- - Use `db-exec UPDATE` for short columns, multi-column writes, or computed updates.
92
+ - Use domain actions first. They validate input, enforce access, and refresh the UI.
93
+ - Use `db-exec UPDATE` only when no domain action exists and you need a small ad-hoc change.
86
94
  - Use `db-patch` when you only need to tweak a small slice of a **large** text/JSON column (documents, slide HTML, dashboard/form JSON). It saves tokens by sending `{find, replace}` instead of re-transmitting the whole column. Targets exactly one row per call — narrow `--where` by primary key. Supports `--edits '[{find,replace},...]'` for batch edits and `--all` for replace-every-occurrence.
87
95
  - If a template-specific action exists (e.g. `edit-document`, `update-slide`), prefer it — those also push live updates to any open collaborative editor.
88
96
 
@@ -110,12 +110,14 @@ agentChat.submit("Generate something");
110
110
 
111
111
  ## Database
112
112
 
113
- By default, data is stored in SQLite at `data/app.db`. For production/cloud deployment, set `DATABASE_URL` to point to a remote database (Turso, Neon, Supabase, D1).
113
+ Local development defaults to a SQLite file at `data/app.db`. That local file is for development; containers, previews, and serverless deploys can reset their filesystem. For production/cloud deployment, set `DATABASE_URL` to point to a persistent SQL database. Turso is optional, not required; common choices include Neon, Supabase, Turso/libSQL, plain Postgres, durable SQLite, D1 bindings, and Builder.io-managed environments when available.
114
114
 
115
- | Variable | Required | Description |
116
- | --------------------- | ---------------- | ---------------------------------------------------------- |
117
- | `DATABASE_URL` | No (has default) | Database connection string (default: `file:./data/app.db`) |
118
- | `DATABASE_AUTH_TOKEN` | For remote DBs | Auth token for Turso or other remote databases |
115
+ When adding app data, define tables with `@agent-native/core/db/schema` helpers and use Drizzle's query builder for reads/writes. Do not import dialect-specific schema helpers from `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core`, and do not write raw SQL in normal actions or handlers when Drizzle can express the query. Raw SQL belongs in additive migrations, health checks, or carefully scoped maintenance.
116
+
117
+ | Variable | Required | Description |
118
+ | --------------------- | ------------------------------- | -------------------------------------------------------------------------- |
119
+ | `DATABASE_URL` | Production yes, local dev no | Persistent SQL connection string (local dev default: `file:./data/app.db`) |
120
+ | `DATABASE_AUTH_TOKEN` | Only when the provider needs it | Auth token for providers such as Turso/libSQL |
119
121
 
120
122
  ## Tech Stack
121
123
 
@@ -77,6 +77,13 @@ the same data unless the route is for uploads, streaming, webhooks, OAuth, or
77
77
  another route-only concern. Action-backed UI is what makes agent-created or
78
78
  agent-edited records appear without a manual refresh.
79
79
 
80
+ App database code must be provider-agnostic. Define schemas with
81
+ `@agent-native/core/db/schema` helpers and write app reads/writes with Drizzle's
82
+ query builder and portable `drizzle-orm` operators. Do not import from
83
+ `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core` in app templates. Keep raw SQL
84
+ for additive migrations, health checks, or carefully scoped maintenance, and
85
+ never write SQLite-only or Postgres-only product code.
86
+
80
87
  In local development, run
81
88
  `pnpm exec agent-native create <app-name> --template=<template>` from the
82
89
  workspace root. In production, Dispatch posts new-app requests to Builder
@@ -102,6 +102,12 @@ coding agents can discover the same workspace-wide guidance from the root.
102
102
  for the same data unless the route is for uploads, streaming, webhooks,
103
103
  OAuth, or another route-only concern. Action-backed UI is what makes
104
104
  agent-created or agent-edited records appear without a manual refresh.
105
+ - App database code must be provider-agnostic. Define schemas with
106
+ `@agent-native/core/db/schema` helpers and write app reads/writes with
107
+ Drizzle's query builder and portable `drizzle-orm` operators. Do not import
108
+ from `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core` in app templates.
109
+ Keep raw SQL for additive migrations, health checks, or carefully scoped
110
+ maintenance, and never write SQLite-only or Postgres-only product code.
105
111
  - In local development, scaffold the app from the workspace root with
106
112
  `pnpm exec agent-native create <app-id> --template=<template>`. In production
107
113
  Dispatch posts the request to Builder branch creation; the Builder branch
@@ -70,7 +70,7 @@ Do not add a `data/` directory for application state. Durable app data belongs i
70
70
 
71
71
  ## Model Data In SQL {#data-models}
72
72
 
73
- Define domain tables with the framework Drizzle helpers so schemas stay portable across SQLite, Postgres, D1, Turso, Supabase, and Neon:
73
+ Define domain tables with the framework Drizzle helpers so schemas stay portable across SQLite, Postgres, D1, Turso, Supabase, Neon, and other supported backends:
74
74
 
75
75
  ```ts
76
76
  // server/db/schema.ts
@@ -102,14 +102,17 @@ export const projectShares = createSharesTable("project_shares", "project");
102
102
 
103
103
  Schema changes must be additive. Add tables and columns through `runMigrations()` in `server/plugins/db.ts`; never use destructive SQL, `drizzle-kit push`, table renames, or column drops.
104
104
 
105
+ For app reads and writes, use Drizzle's query builder and portable operators from `drizzle-orm`. Do not write product code with raw SQL when Drizzle can express the query, and do not import from `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core` in templates.
106
+
105
107
  ```ts
106
108
  // server/plugins/db.ts
107
- import { runMigrations } from "@agent-native/core/db/migrations";
109
+ import { runMigrations } from "@agent-native/core/db";
108
110
 
109
- export default runMigrations([
110
- {
111
- id: "001_create_projects",
112
- sql: `CREATE TABLE IF NOT EXISTS projects (
111
+ export default runMigrations(
112
+ [
113
+ {
114
+ version: 1,
115
+ sql: `CREATE TABLE IF NOT EXISTS projects (
113
116
  id TEXT PRIMARY KEY,
114
117
  title TEXT NOT NULL,
115
118
  status TEXT NOT NULL DEFAULT 'draft',
@@ -120,8 +123,10 @@ export default runMigrations([
120
123
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
121
124
  updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
122
125
  )`,
123
- },
124
- ]);
126
+ },
127
+ ],
128
+ { table: "my_app_migrations" },
129
+ );
125
130
  ```
126
131
 
127
132
  Use the [Database](/docs/database) and [Security](/docs/security) docs before adding schemas that hold user or org data.
@@ -273,7 +278,7 @@ Projects are the top-level resource. They contain tasks and notes.
273
278
  ## Rules
274
279
 
275
280
  - Use `view-screen` before acting on "this project" if the current screen is unclear.
276
- - Use actions for project changes; do not write raw SQL unless debugging.
281
+ - Use actions for project changes; do not write raw SQL except for one-off maintenance/debugging when no action exists.
277
282
  - For shared projects, check access through framework sharing helpers.
278
283
  ```
279
284
 
@@ -1,19 +1,21 @@
1
1
  ---
2
2
  title: "Database"
3
- description: "Connect any SQL database to your agent-native app SQLite for local dev, Postgres for production."
3
+ description: "Connect a portable SQL database to your agent-native app and write provider-agnostic Drizzle code."
4
4
  ---
5
5
 
6
6
  # Database
7
7
 
8
- Agent-native apps use [Drizzle ORM](https://orm.drizzle.team) and support any SQL database. By default, apps use SQLite with a local file — set `DATABASE_URL` to connect a production database.
8
+ Agent-native apps use [Drizzle ORM](https://orm.drizzle.team) and support portable SQL backends. By default, apps use SQLite with a local file — set `DATABASE_URL` to connect a persistent production database.
9
9
 
10
10
  ## Default: SQLite {#default-sqlite}
11
11
 
12
12
  When `DATABASE_URL` is not set, the app creates a SQLite database at `data/app.db`. This is great for local development — no setup required.
13
13
 
14
+ Do not rely on that local file for deployed apps. Containers, serverless functions, and preview environments may reset their filesystem, which means a local SQLite file can disappear between restarts. Set `DATABASE_URL` to a persistent hosted database before production use.
15
+
14
16
  ## Connecting a Production Database {#production}
15
17
 
16
- Set `DATABASE_URL` in your `.env` file to connect a hosted database:
18
+ Set `DATABASE_URL` in your `.env` file or deploy-provider environment to connect a hosted database. Turso is not required; use whichever Drizzle-compatible SQL backend fits your deployment:
17
19
 
18
20
  ```bash
19
21
  # Neon Postgres
@@ -27,18 +29,18 @@ DATABASE_URL=postgres://user:pass@localhost:5432/mydb
27
29
 
28
30
  # Turso (libSQL)
29
31
  DATABASE_URL=libsql://my-db-org.turso.io
30
- TURSO_AUTH_TOKEN=your-token
32
+ DATABASE_AUTH_TOKEN=your-token
31
33
  ```
32
34
 
33
- The framework auto-detects the dialect from the URL and configures Drizzle accordingly.
35
+ The framework auto-detects the dialect from the URL and configures Drizzle accordingly. The built-in adapters cover Postgres URLs, libSQL/Turso URLs, SQLite file URLs, and Cloudflare D1 bindings. Common production choices include Neon, Supabase, Turso/libSQL, plain Postgres, durable SQLite, and Builder.io-managed environments when available.
34
36
 
35
37
  ## Builder.io Managed Database {#builder-managed}
36
38
 
37
39
  When connected to Builder.io, your app can use a managed database that is provisioned and scaled automatically. This is the simplest path to production — no connection strings or database admin required. Coming soon.
38
40
 
39
- ## Dialect-Agnostic Schema {#schema}
41
+ ## Dialect-Agnostic Schema And Queries {#schema}
40
42
 
41
- All SQL must work on both SQLite and Postgres. Never use SQLite-only syntax (`INSERT OR REPLACE`, `AUTOINCREMENT`, `datetime('now')`) or Postgres-only syntax.
43
+ App database code should use Drizzle's schema and query DSL so it can run across providers. Never write SQLite-only syntax (`INSERT OR REPLACE`, `AUTOINCREMENT`, `datetime('now')`) or Postgres-only syntax in product code.
42
44
 
43
45
  Use the framework's schema helpers from `@agent-native/core/db/schema`:
44
46
 
@@ -66,9 +68,29 @@ export const tasks = table("tasks", {
66
68
 
67
69
  Never import from `drizzle-orm/sqlite-core` or `drizzle-orm/pg-core` directly. Always use `@agent-native/core/db/schema`.
68
70
 
69
- ## Raw SQL Helpers {#raw-sql}
71
+ For reads and writes, use Drizzle's query builder and portable operators from `drizzle-orm`:
72
+
73
+ ```ts
74
+ import { and, desc, eq } from "drizzle-orm";
75
+ import { getDb } from "../server/db/index.js";
76
+ import { tasks } from "../server/db/schema.js";
77
+
78
+ const db = getDb();
79
+
80
+ const openTasks = await db
81
+ .select()
82
+ .from(tasks)
83
+ .where(and(eq(tasks.ownerEmail, userEmail), eq(tasks.done, false)))
84
+ .orderBy(desc(tasks.createdAt));
70
85
 
71
- For cases where you need raw SQL outside of Drizzle queries:
86
+ await db.update(tasks).set({ done: true }).where(eq(tasks.id, taskId));
87
+ ```
88
+
89
+ ## Raw SQL Escape Hatches {#raw-sql}
90
+
91
+ Raw SQL is not the default app-code API. Use it only for additive migrations, health checks, carefully reviewed advanced queries that Drizzle cannot express, or one-off maintenance. Keep it parameterized and dialect-agnostic. For timestamps in Drizzle schemas, prefer `.default(now())`; for migration SQL, use `runMigrations()` so framework-supported compatibility rewrites and dialect-gated statements stay centralized.
92
+
93
+ For cases where you truly need raw SQL outside of Drizzle queries:
72
94
 
73
95
  - `getDbExec()` — auto-converts `?` params to `$1` for Postgres
74
96
  - `isPostgres()` — runtime dialect check
@@ -97,15 +119,20 @@ Instead of pushing directly, schema changes should be applied via SQL migrations
97
119
  ```ts
98
120
  import { runMigrations } from "@agent-native/core/db";
99
121
 
100
- export default defineNitroPlugin(async () => {
101
- // Executes pending SQL migrations safely at startup
102
- await runMigrations();
103
- });
122
+ export default runMigrations(
123
+ [
124
+ {
125
+ version: 1,
126
+ sql: `ALTER TABLE projects ADD COLUMN IF NOT EXISTS sort_order INTEGER NOT NULL DEFAULT 0`,
127
+ },
128
+ ],
129
+ { table: "my_app_migrations" },
130
+ );
104
131
  ```
105
132
 
106
133
  ## Environment Variables {#environment-variables}
107
134
 
108
- | Variable | Purpose |
109
- | ------------------ | ------------------------------------------------- |
110
- | `DATABASE_URL` | Database connection string (unset = local SQLite) |
111
- | `TURSO_AUTH_TOKEN` | Auth token for Turso (libSQL) databases |
135
+ | Variable | Purpose |
136
+ | --------------------- | ---------------------------------------------------------------------------------------------------- |
137
+ | `DATABASE_URL` | Persistent SQL connection string (unset = local SQLite, which is only durable for local development) |
138
+ | `DATABASE_AUTH_TOKEN` | Auth token for providers that require a separate token, such as Turso/libSQL |
@@ -7,6 +7,14 @@ description: "Deploy agent-native apps to any platform with Nitro presets — No
7
7
 
8
8
  Agent-native apps use [Nitro](https://nitro.build) under the hood, which means you can deploy to any platform with zero config changes — just set a preset.
9
9
 
10
+ ## Before You Deploy: Pick a Persistent Database {#persistent-database}
11
+
12
+ Every deployed app needs a persistent SQL database. In local development, agent-native falls back to a SQLite file at `data/app.db`; that is convenient on your machine, but it is not durable in containers, previews, or serverless environments where the filesystem can be reset.
13
+
14
+ Set `DATABASE_URL` in your deploy provider before promoting an app to production. Agent-native uses Drizzle for schema and queries, so the data layer is portable across Drizzle-compatible SQL backends. The built-in adapters auto-detect Postgres URLs, libSQL/Turso URLs, SQLite file URLs, and Cloudflare D1 bindings. Common choices include Neon or Supabase Postgres, Turso/libSQL, plain Postgres, durable SQLite, and Builder.io-managed environments when available. Turso is one option, not a requirement.
15
+
16
+ Use `DATABASE_AUTH_TOKEN` only when your database provider requires a separate token, such as Turso/libSQL. For workspaces, all apps inherit the root `DATABASE_URL` by default; set `<APP_NAME>_DATABASE_URL` when one app should use a different database.
17
+
10
18
  ## Workspace Deploy: One Origin, Many Apps {#workspace-deploy}
11
19
 
12
20
  If your project is a [workspace](/docs/multi-app-workspace), you can ship every app in it to a single origin with one command:
@@ -200,13 +208,13 @@ export default defineConfig({
200
208
 
201
209
  ### Build / Runtime {#env-runtime}
202
210
 
203
- | Variable | Description |
204
- | --------------------- | -------------------------------------------------------------------------------------------------------------------- |
205
- | `PORT` | Server port (Node.js only) |
206
- | `NITRO_PRESET` | Override build preset at build time |
207
- | `APP_BASE_PATH` | Mount the app under a prefix (e.g. `/mail`). Set automatically by `agent-native deploy`; leave unset for standalone. |
208
- | `DATABASE_URL` | Postgres / Turso / SQLite connection string. Required in production. |
209
- | `DATABASE_AUTH_TOKEN` | Auth token for Turso / libsql connections. |
211
+ | Variable | Description |
212
+ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
213
+ | `PORT` | Server port (Node.js only) |
214
+ | `NITRO_PRESET` | Override build preset at build time |
215
+ | `APP_BASE_PATH` | Mount the app under a prefix (e.g. `/mail`). Set automatically by `agent-native deploy`; leave unset for standalone. |
216
+ | `DATABASE_URL` | Persistent SQL connection string. Required in production; common options include Neon, Supabase, Turso/libSQL, plain Postgres, durable SQLite, and Builder.io-managed environments when available. |
217
+ | `DATABASE_AUTH_TOKEN` | Auth token for providers that require a separate token, such as Turso/libSQL. |
210
218
 
211
219
  ### Required in Production {#env-required-prod}
212
220
 
@@ -19,7 +19,7 @@ Reach for Dispatch when any of these are true:
19
19
  - You want **one inbox for "the agent"** so users DM a single bot and the right specialist app picks up the work behind the scenes.
20
20
  - You have **workspace-wide secrets** (Stripe key, OpenAI key, third-party API tokens) that several apps need and you want one vault instead of copying values into every `.env`.
21
21
  - You want a **runtime approval flow** in front of sensitive changes (saved destinations, policy edits) so non-admins can request and admins can sign off without a code deploy.
22
- - You want **shared skills, instructions, and agent profiles** that every app in the workspace inherits — change once, reach all.
22
+ - You want **shared skills, instructions, agent profiles, and MCP servers** that apps in the workspace inherit — change once, reach all.
23
23
 
24
24
  If you're running a single template standalone, you don't need Dispatch — each template can wire its own messaging integrations directly. See [Messaging](/docs/messaging) for the standalone setup.
25
25
 
@@ -76,6 +76,7 @@ Use the canonical paths to control how agents consume them:
76
76
  - `skills/<slug>/SKILL.md` for on-demand skills available through `/` commands and the prompt skill index
77
77
  - `context/<slug>.md` for brand, persona, positioning, messaging, company facts, and other reference material the agent reads when relevant
78
78
  - `agents/<slug>.md` for reusable custom agent profiles
79
+ - `mcp-servers/<slug>.json` for HTTP MCP servers that should add external tools to granted app agents
79
80
 
80
81
  Starter global resources usually look like:
81
82
 
@@ -89,6 +90,11 @@ skills/company-voice/SKILL.md
89
90
 
90
91
  Set these to **All apps** when every app should inherit the same company facts, brand rules, messaging, safety constraints, and customer-facing writing style. Use selected-app grants only for resources that are genuinely app-specific.
91
92
 
93
+ MCP server resources use JSON and are intentionally HTTP-only. Store tokens in
94
+ Dispatch Vault, grant or sync those keys to the target apps, and reference them
95
+ from headers with `${keys.NAME}` so the raw credential never lives in the
96
+ resource body.
97
+
92
98
  The **Resources** page highlights this starter pack in a Global context section so admins can quickly see which files exist, whether they are scoped to all apps, restore missing starter files without overwriting existing ones, and edit their contents. Expand any resource to preview its effective runtime stack for a selected app/user: workspace default, organization/app override, then personal override. Each app card also has a **Context** view that shows exactly what that app receives: inherited workspace resources, selected grants, and auto-loaded instructions. Use a resource row's **Stack** control to inspect which layer wins for that app.
93
99
 
94
100
  This is how a team-wide change ("always use British English in customer-facing replies") or a shared brand guideline propagates without editing ten repos.
@@ -14,6 +14,85 @@ Use it when you want an assistant that can:
14
14
  - Ask the host app to navigate, refresh data, remount a view, or open a resource after durable work completes.
15
15
  - Run as an iframe/sidebar now, while leaving room for a no-iframe package or hosted template later.
16
16
 
17
+ ## Embedded App And Picker Mode
18
+
19
+ Use `@agent-native/embedding` when the host product wants to launch a complete
20
+ Agent-Native app as a focused iframe surface: an asset picker, asset generator,
21
+ form builder, calendar slot picker, approval panel, or any other task-specific
22
+ workflow. This is intentionally smaller than the sidecar host bridge below: the
23
+ iframe announces readiness, the host can send named messages, and the embedded
24
+ app can emit domain events such as `chooseAsset` or `close`.
25
+
26
+ ```tsx
27
+ import { EmbeddedApp } from "@agent-native/embedding";
28
+
29
+ export function AssetPickerDialog({ close }) {
30
+ return (
31
+ <EmbeddedApp
32
+ url="https://assets.agent-native.com/picker"
33
+ className="h-full w-full"
34
+ onLoad={(ref) => {
35
+ ref.postMessage("configure", {
36
+ prompt: "Editorial blog hero",
37
+ aspectRatio: "16:9",
38
+ });
39
+ }}
40
+ onMessage={(name, payload) => {
41
+ if (name === "chooseAsset") {
42
+ const asset = payload as { url: string; altText?: string };
43
+ insertAsset(asset.url, asset.altText);
44
+ close();
45
+ }
46
+ if (name === "close") close();
47
+ }}
48
+ />
49
+ );
50
+ }
51
+ ```
52
+
53
+ Inside the embedded app, use the browser bridge to announce readiness and send
54
+ events back to the host:
55
+
56
+ ```ts
57
+ import {
58
+ announceEmbeddedAppReady,
59
+ sendEmbeddedAppMessage,
60
+ } from "@agent-native/embedding/bridge";
61
+
62
+ announceEmbeddedAppReady({ app: "assets", mode: "picker" });
63
+ sendEmbeddedAppMessage("chooseAsset", {
64
+ url: asset.previewUrl,
65
+ assetId: asset.id,
66
+ altText: asset.altText,
67
+ });
68
+ ```
69
+
70
+ Assets also emits `chooseImage` as a compatibility alias for older image-picker
71
+ hosts; new integrations should listen for `chooseAsset`.
72
+
73
+ For hosted first-party apps, enable Cross-App SSO with Dispatch as the identity
74
+ hub so `content.agent-native.com` and `assets.agent-native.com` link users by
75
+ verified email. Iframe launches should still use short-lived, route-scoped
76
+ embed sessions when they need third-party-cookie resilience; normal app cookies
77
+ are not a complete embed auth story on their own.
78
+
79
+ The same package includes agent endpoint helpers for protocol discovery and
80
+ streaming text over A2A:
81
+
82
+ ```ts
83
+ import { getA2AUrl, getMcpUrl, sendMessage } from "@agent-native/embedding";
84
+
85
+ getMcpUrl("https://assets.agent-native.com");
86
+ getA2AUrl("https://assets.agent-native.com");
87
+
88
+ for await (const chunk of sendMessage(
89
+ "https://assets.agent-native.com",
90
+ "Generate a blog hero",
91
+ )) {
92
+ append(chunk);
93
+ }
94
+ ```
95
+
17
96
  ## Batteries-Included Embedded Mode
18
97
 
19
98
  For most SaaS hosts, use the full embedded runtime. The host mounts Agent-Native server routes into its existing app, passes its logged-in user to Agent-Native, and then renders the React sidebar/surface in the product UI. Agent-Native uses the host deployment, host session, and the configured `DATABASE_URL` to manage its own framework tables: chat threads, settings, application state, extensions, extension data, secrets, browser sessions, and action routes.
@@ -130,6 +130,11 @@ If the extension needs an API key — a CRM token, a weather API — the agent t
130
130
 
131
131
  If you want to change something later, just say so: "Add a search box to my contact notes." The agent edits the HTML in place — no regeneration of the whole thing.
132
132
 
133
+ Every change is versioned. Open the extension viewer's History control to see
134
+ saved versions, inspect the diff from the previous version, and restore an
135
+ older name/description/icon/content snapshot without changing ownership or
136
+ sharing.
137
+
133
138
  ## What an extension can do {#capabilities}
134
139
 
135
140
  Inside the iframe sandbox, every extension has these helpers on `window`:
@@ -96,10 +96,10 @@ export const forms = table("forms", {
96
96
  ```
97
97
 
98
98
  ```bash
99
- # Core actions for quick database access
99
+ # Core actions for quick database inspection and one-off maintenance
100
100
  pnpm action db-schema # show all tables
101
101
  pnpm action db-query --sql "SELECT * FROM forms"
102
- pnpm action db-exec --sql "INSERT INTO forms ..."
102
+ pnpm action db-exec --sql "UPDATE forms SET status = ? WHERE id = ?" --args '["closed","form-1"]'
103
103
  # Surgical find/replace on a large text column — sends a diff, not the whole value
104
104
  pnpm action db-patch --table documents --column content \
105
105
  --where "id='doc-1'" --find "old heading" --replace "new heading"
@@ -227,7 +227,7 @@ There's no shared codebase to break. You own the app, and the agent evolves it f
227
227
 
228
228
  ## Database agnostic {#database-agnostic}
229
229
 
230
- The framework supports every Drizzle-supported database. Never write SQL that only works on one dialect.
230
+ The framework supports portable Drizzle-backed SQL databases. Write app schemas with `@agent-native/core/db/schema` and app reads/writes with Drizzle's query builder so code can run across providers.
231
231
 
232
232
  - **SQLite** — local dev fallback when `DATABASE_URL` is unset
233
233
  - **Neon Postgres** — common in both dev and production
@@ -236,24 +236,22 @@ The framework supports every Drizzle-supported database. Never write SQL that on
236
236
  - **Cloudflare D1**
237
237
  - **Plain Postgres**
238
238
 
239
- Use the framework helpers for dialect-agnostic SQL:
239
+ Use Drizzle's portable query DSL for normal app code:
240
240
 
241
241
  ```ts
242
- import { getDbExec, isPostgres, intType } from "@agent-native/core/db";
243
-
244
- // getDbExec() auto-converts ? params to $1 for Postgres
245
- const client = getDbExec();
246
- await client.execute({
247
- sql: "SELECT * FROM forms WHERE owner_email = ?",
248
- args: [email],
249
- });
250
-
251
- // Branch when syntax differs
252
- const upsert = isPostgres()
253
- ? "INSERT INTO settings (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = $2"
254
- : "INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)";
242
+ import { and, desc, eq } from "drizzle-orm";
243
+
244
+ const forms = await db
245
+ .select()
246
+ .from(schema.forms)
247
+ .where(
248
+ and(eq(schema.forms.ownerEmail, email), eq(schema.forms.status, "open")),
249
+ )
250
+ .orderBy(desc(schema.forms.createdAt));
255
251
  ```
256
252
 
253
+ Use raw SQL only for additive migrations, health checks, or one-off maintenance, and keep it parameterized and dialect-agnostic.
254
+
257
255
  ## Hosting agnostic {#hosting-agnostic}
258
256
 
259
257
  The server runs on Nitro, which compiles to any deployment target:
@@ -159,6 +159,36 @@ If your workspace runs multiple agent-native apps (e.g. dispatch + mail + clips)
159
159
 
160
160
  Dispatch is the conventional hub — it already coordinates across apps.
161
161
 
162
+ For new workspace setups, prefer **Dispatch workspace MCP resources** when you
163
+ want the same All-app vs selected-app grant model used by workspace skills,
164
+ instructions, and reference resources. Add a workspace resource with:
165
+
166
+ ```json
167
+ {
168
+ "type": "http",
169
+ "url": "https://example.com/mcp",
170
+ "headers": {
171
+ "Authorization": "Bearer ${keys.MCP_SERVER_TOKEN}"
172
+ },
173
+ "description": "Shared MCP tools for workspace apps"
174
+ }
175
+ ```
176
+
177
+ Save it under `mcp-servers/<name>.json` with kind `mcp-server`. All-app
178
+ resources are loaded by every workspace app; selected resources load only in
179
+ apps with an active Dispatch grant. Secret placeholders resolve from the app
180
+ secret store, so put raw bearer tokens in Dispatch Vault and reference them
181
+ with `${keys.NAME}` instead of storing them in the resource body.
182
+
183
+ Apps refresh their merged MCP config about once a minute, so central resource
184
+ edits, grant changes, and removals take effect without a deploy. Set
185
+ `AGENT_NATIVE_MCP_CONFIG_REFRESH_MS=0` to disable that background refresh, or
186
+ set it to a value of at least `5000` milliseconds to tune the interval.
187
+
188
+ The older hub mode below remains useful for coarse “share every org-scope MCP
189
+ server from Dispatch” setups and for deployments that already use the MCP
190
+ settings UI as the source of truth.
191
+
162
192
  ### 1. Enable hub-serve on the hub app (dispatch)
163
193
 
164
194
  Set an env var in dispatch's deployment:
@@ -141,7 +141,7 @@ Use `packages/shared` for code-level defaults that should ship with the repo: pl
141
141
  Dispatch resources support two scopes:
142
142
 
143
143
  - **All apps** — global resources for every app in the workspace. Dispatch stores them once at workspace scope and every app agent inherits them at runtime; no copy or sync step is required.
144
- - **Selected apps** — resources granted per app for app-specific context. Use these sparingly; most company, brand, persona, positioning, messaging, and guardrail context should be All apps.
144
+ - **Selected apps** — resources granted per app for app-specific context or tools. Use these sparingly; most company, brand, persona, positioning, messaging, and guardrail context should be All apps.
145
145
 
146
146
  Canonical paths control behavior:
147
147
 
@@ -151,8 +151,9 @@ Canonical paths control behavior:
151
151
  | Global skills | `skills/<slug>/SKILL.md` | Listed as workspace skills and read on demand |
152
152
  | Brand/company resources | `context/<slug>.md` | Indexed every turn, read when relevant |
153
153
  | Custom agent profiles | `agents/<slug>.md` | Available as reusable local agent profiles |
154
+ | Shared HTTP MCP servers | `mcp-servers/<slug>.json` | Loaded into granted apps' MCP tool registry |
154
155
 
155
- This is the right home for core personas, positioning, messaging, company facts, brand guidelines, support policies, or other shared knowledge that many apps should benefit from.
156
+ This is the right home for core personas, positioning, messaging, company facts, brand guidelines, support policies, shared skills, or shared HTTP MCP tools that many apps should benefit from.
156
157
 
157
158
  For a starter workspace, create these Dispatch resources and scope them to **All apps**:
158
159
 
@@ -54,15 +54,15 @@ For full details on how scoping works at the SQL level, see [Security & Data Sco
54
54
 
55
55
  ## Adding multi-tenancy to a new table {#new-tables}
56
56
 
57
- When you add a new domain table, include `organization_id` to make it tenant-aware:
57
+ When you add a new domain table, use the framework's dialect-agnostic schema helpers and include ownership columns to make it tenant-aware:
58
58
 
59
59
  ```typescript
60
- import { sqliteTable, text } from "drizzle-orm/sqlite-core";
60
+ import { table, text, ownableColumns } from "@agent-native/core/db/schema";
61
61
 
62
- export const projects = sqliteTable("projects", {
62
+ export const projects = table("projects", {
63
63
  id: text("id").primaryKey(),
64
64
  title: text("title").notNull(),
65
- organizationId: text("organization_id").notNull(),
65
+ ...ownableColumns(),
66
66
  // ... other columns
67
67
  });
68
68
  ```
@@ -94,20 +94,23 @@ Plugins live in `server/plugins/` and run at startup. Use them for migrations, p
94
94
 
95
95
  ```ts
96
96
  // server/plugins/db.ts
97
- import { runMigrations } from "@agent-native/core/db/migrations";
97
+ import { runMigrations } from "@agent-native/core/db";
98
98
 
99
- export default runMigrations([
100
- {
101
- id: "001_create_projects",
102
- sql: `CREATE TABLE IF NOT EXISTS projects (
99
+ export default runMigrations(
100
+ [
101
+ {
102
+ version: 1,
103
+ sql: `CREATE TABLE IF NOT EXISTS projects (
103
104
  id TEXT PRIMARY KEY,
104
105
  title TEXT NOT NULL,
105
106
  owner_email TEXT NOT NULL,
106
107
  org_id TEXT,
107
108
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
108
109
  )`,
109
- },
110
- ]);
110
+ },
111
+ ],
112
+ { table: "my_app_migrations" },
113
+ );
111
114
  ```
112
115
 
113
116
  Migrations must be additive. Never put destructive SQL in startup plugins.