@agent-native/core 0.9.1 → 0.11.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 (288) hide show
  1. package/README.md +4 -4
  2. package/dist/a2a/caller-auth.d.ts +12 -0
  3. package/dist/a2a/caller-auth.d.ts.map +1 -0
  4. package/dist/a2a/caller-auth.js +54 -0
  5. package/dist/a2a/caller-auth.js.map +1 -0
  6. package/dist/action.d.ts +17 -0
  7. package/dist/action.d.ts.map +1 -1
  8. package/dist/action.js +22 -0
  9. package/dist/action.js.map +1 -1
  10. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  11. package/dist/agent/engine/builder-engine.js +5 -4
  12. package/dist/agent/engine/builder-engine.js.map +1 -1
  13. package/dist/agent/engine/registry.d.ts +6 -3
  14. package/dist/agent/engine/registry.d.ts.map +1 -1
  15. package/dist/agent/engine/registry.js +8 -17
  16. package/dist/agent/engine/registry.js.map +1 -1
  17. package/dist/agent/production-agent.d.ts +1 -1
  18. package/dist/agent/production-agent.d.ts.map +1 -1
  19. package/dist/agent/production-agent.js +60 -30
  20. package/dist/agent/production-agent.js.map +1 -1
  21. package/dist/agent/run-manager.d.ts.map +1 -1
  22. package/dist/agent/run-manager.js +12 -3
  23. package/dist/agent/run-manager.js.map +1 -1
  24. package/dist/agent/thread-data-builder.d.ts +12 -0
  25. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  26. package/dist/agent/thread-data-builder.js +96 -0
  27. package/dist/agent/thread-data-builder.js.map +1 -1
  28. package/dist/cli/create.d.ts.map +1 -1
  29. package/dist/cli/create.js +16 -10
  30. package/dist/cli/create.js.map +1 -1
  31. package/dist/client/AgentPanel.d.ts.map +1 -1
  32. package/dist/client/AgentPanel.js +8 -22
  33. package/dist/client/AgentPanel.js.map +1 -1
  34. package/dist/client/AssistantChat.d.ts.map +1 -1
  35. package/dist/client/AssistantChat.js +130 -34
  36. package/dist/client/AssistantChat.js.map +1 -1
  37. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  38. package/dist/client/agent-chat-adapter.js +21 -7
  39. package/dist/client/agent-chat-adapter.js.map +1 -1
  40. package/dist/client/agent-sidebar-state.d.ts +3 -0
  41. package/dist/client/agent-sidebar-state.d.ts.map +1 -0
  42. package/dist/client/agent-sidebar-state.js +24 -0
  43. package/dist/client/agent-sidebar-state.js.map +1 -0
  44. package/dist/client/analytics.d.ts +25 -0
  45. package/dist/client/analytics.d.ts.map +1 -1
  46. package/dist/client/analytics.js +40 -0
  47. package/dist/client/analytics.js.map +1 -1
  48. package/dist/client/components/ui/dropdown-menu.d.ts +28 -0
  49. package/dist/client/components/ui/dropdown-menu.d.ts.map +1 -0
  50. package/dist/client/components/ui/dropdown-menu.js +34 -0
  51. package/dist/client/components/ui/dropdown-menu.js.map +1 -0
  52. package/dist/client/components/ui/tooltip.d.ts +2 -1
  53. package/dist/client/components/ui/tooltip.d.ts.map +1 -1
  54. package/dist/client/components/ui/tooltip.js +9 -2
  55. package/dist/client/components/ui/tooltip.js.map +1 -1
  56. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  57. package/dist/client/composer/ComposerPlusMenu.js +41 -8
  58. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  59. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  60. package/dist/client/composer/PromptComposer.js +30 -0
  61. package/dist/client/composer/PromptComposer.js.map +1 -1
  62. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  63. package/dist/client/composer/TiptapComposer.js +27 -2
  64. package/dist/client/composer/TiptapComposer.js.map +1 -1
  65. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  66. package/dist/client/dev-overlay/DevOverlay.js +4 -4
  67. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  68. package/dist/client/error-format.d.ts.map +1 -1
  69. package/dist/client/error-format.js +6 -0
  70. package/dist/client/error-format.js.map +1 -1
  71. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  72. package/dist/client/extensions/EmbeddedExtension.js +16 -4
  73. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  74. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  75. package/dist/client/extensions/ExtensionEditor.js +6 -6
  76. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  77. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  78. package/dist/client/extensions/ExtensionSlot.js +15 -2
  79. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  80. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  81. package/dist/client/extensions/ExtensionViewer.js +41 -19
  82. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  83. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  84. package/dist/client/extensions/ExtensionsListPage.js +2 -2
  85. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  86. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  87. package/dist/client/extensions/ExtensionsSidebarSection.js +52 -63
  88. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  89. package/dist/client/extensions/iframe-bridge.d.ts.map +1 -1
  90. package/dist/client/extensions/iframe-bridge.js +5 -8
  91. package/dist/client/extensions/iframe-bridge.js.map +1 -1
  92. package/dist/client/index.d.ts +1 -1
  93. package/dist/client/index.d.ts.map +1 -1
  94. package/dist/client/index.js +1 -1
  95. package/dist/client/index.js.map +1 -1
  96. package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
  97. package/dist/client/notifications/NotificationsBell.js +42 -6
  98. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  99. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  100. package/dist/client/org/InvitationBanner.js +5 -5
  101. package/dist/client/org/InvitationBanner.js.map +1 -1
  102. package/dist/client/org/OrgSwitcher.d.ts +7 -1
  103. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  104. package/dist/client/org/OrgSwitcher.js +8 -3
  105. package/dist/client/org/OrgSwitcher.js.map +1 -1
  106. package/dist/client/org/TeamPage.d.ts.map +1 -1
  107. package/dist/client/org/TeamPage.js +156 -22
  108. package/dist/client/org/TeamPage.js.map +1 -1
  109. package/dist/client/org/hooks.d.ts +29 -1
  110. package/dist/client/org/hooks.d.ts.map +1 -1
  111. package/dist/client/org/hooks.js +39 -2
  112. package/dist/client/org/hooks.js.map +1 -1
  113. package/dist/client/org/index.d.ts +2 -1
  114. package/dist/client/org/index.d.ts.map +1 -1
  115. package/dist/client/org/index.js +1 -1
  116. package/dist/client/org/index.js.map +1 -1
  117. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  118. package/dist/client/resources/ResourceTree.js +11 -3
  119. package/dist/client/resources/ResourceTree.js.map +1 -1
  120. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  121. package/dist/client/resources/ResourcesPanel.js +62 -12
  122. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  123. package/dist/client/resources/use-mcp-servers.d.ts +2 -0
  124. package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
  125. package/dist/client/resources/use-mcp-servers.js +59 -3
  126. package/dist/client/resources/use-mcp-servers.js.map +1 -1
  127. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  128. package/dist/client/settings/SecretsSection.js +9 -0
  129. package/dist/client/settings/SecretsSection.js.map +1 -1
  130. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  131. package/dist/client/settings/SettingsPanel.js +50 -12
  132. package/dist/client/settings/SettingsPanel.js.map +1 -1
  133. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  134. package/dist/client/settings/VoiceTranscriptionSection.js +13 -30
  135. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  136. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  137. package/dist/client/settings/useBuilderStatus.js +27 -1
  138. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  139. package/dist/client/sharing/ShareButton.d.ts +4 -0
  140. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  141. package/dist/client/sharing/ShareButton.js +5 -1
  142. package/dist/client/sharing/ShareButton.js.map +1 -1
  143. package/dist/client/sse-event-processor.d.ts +1 -1
  144. package/dist/client/sse-event-processor.d.ts.map +1 -1
  145. package/dist/client/sse-event-processor.js +14 -7
  146. package/dist/client/sse-event-processor.js.map +1 -1
  147. package/dist/client/use-db-sync.d.ts.map +1 -1
  148. package/dist/client/use-db-sync.js +100 -19
  149. package/dist/client/use-db-sync.js.map +1 -1
  150. package/dist/deploy/build.d.ts.map +1 -1
  151. package/dist/deploy/build.js +25 -49
  152. package/dist/deploy/build.js.map +1 -1
  153. package/dist/deploy/route-discovery.d.ts.map +1 -1
  154. package/dist/deploy/route-discovery.js +1 -0
  155. package/dist/deploy/route-discovery.js.map +1 -1
  156. package/dist/deploy/workspace-core.d.ts +1 -1
  157. package/dist/deploy/workspace-core.d.ts.map +1 -1
  158. package/dist/deploy/workspace-core.js +1 -0
  159. package/dist/deploy/workspace-core.js.map +1 -1
  160. package/dist/extensions/actions.d.ts.map +1 -1
  161. package/dist/extensions/actions.js +17 -3
  162. package/dist/extensions/actions.js.map +1 -1
  163. package/dist/extensions/routes.js +1 -1
  164. package/dist/extensions/routes.js.map +1 -1
  165. package/dist/extensions/schema.d.ts +14 -14
  166. package/dist/extensions/schema.d.ts.map +1 -1
  167. package/dist/extensions/schema.js +4 -4
  168. package/dist/extensions/schema.js.map +1 -1
  169. package/dist/extensions/store.d.ts.map +1 -1
  170. package/dist/extensions/store.js +23 -0
  171. package/dist/extensions/store.js.map +1 -1
  172. package/dist/extensions/theme.d.ts +8 -1
  173. package/dist/extensions/theme.d.ts.map +1 -1
  174. package/dist/extensions/theme.js +43 -34
  175. package/dist/extensions/theme.js.map +1 -1
  176. package/dist/index.browser.d.ts +1 -1
  177. package/dist/index.browser.d.ts.map +1 -1
  178. package/dist/index.browser.js +1 -1
  179. package/dist/index.browser.js.map +1 -1
  180. package/dist/index.d.ts +1 -1
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +1 -1
  183. package/dist/index.js.map +1 -1
  184. package/dist/mcp-client/routes.d.ts +1 -0
  185. package/dist/mcp-client/routes.d.ts.map +1 -1
  186. package/dist/mcp-client/routes.js +28 -1
  187. package/dist/mcp-client/routes.js.map +1 -1
  188. package/dist/org/accept-pending.d.ts.map +1 -1
  189. package/dist/org/accept-pending.js +5 -3
  190. package/dist/org/accept-pending.js.map +1 -1
  191. package/dist/org/free-email-providers.d.ts +18 -0
  192. package/dist/org/free-email-providers.d.ts.map +1 -0
  193. package/dist/org/free-email-providers.js +124 -0
  194. package/dist/org/free-email-providers.js.map +1 -0
  195. package/dist/org/handlers.d.ts +29 -5
  196. package/dist/org/handlers.d.ts.map +1 -1
  197. package/dist/org/handlers.js +178 -37
  198. package/dist/org/handlers.js.map +1 -1
  199. package/dist/org/index.d.ts +2 -1
  200. package/dist/org/index.d.ts.map +1 -1
  201. package/dist/org/index.js +2 -1
  202. package/dist/org/index.js.map +1 -1
  203. package/dist/org/migrations.d.ts.map +1 -1
  204. package/dist/org/migrations.js +4 -0
  205. package/dist/org/migrations.js.map +1 -1
  206. package/dist/org/plugin.d.ts.map +1 -1
  207. package/dist/org/plugin.js +13 -4
  208. package/dist/org/plugin.js.map +1 -1
  209. package/dist/org/schema.d.ts +19 -0
  210. package/dist/org/schema.d.ts.map +1 -1
  211. package/dist/org/schema.js +1 -0
  212. package/dist/org/schema.js.map +1 -1
  213. package/dist/org/types.d.ts +1 -0
  214. package/dist/org/types.d.ts.map +1 -1
  215. package/dist/org/types.js.map +1 -1
  216. package/dist/resources/metadata.d.ts +1 -0
  217. package/dist/resources/metadata.d.ts.map +1 -1
  218. package/dist/resources/metadata.js +13 -3
  219. package/dist/resources/metadata.js.map +1 -1
  220. package/dist/resources/store.d.ts.map +1 -1
  221. package/dist/resources/store.js +44 -6
  222. package/dist/resources/store.js.map +1 -1
  223. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  224. package/dist/server/agent-chat-plugin.js +115 -113
  225. package/dist/server/agent-chat-plugin.js.map +1 -1
  226. package/dist/server/auth.d.ts.map +1 -1
  227. package/dist/server/auth.js +33 -0
  228. package/dist/server/auth.js.map +1 -1
  229. package/dist/server/builder-browser.d.ts.map +1 -1
  230. package/dist/server/builder-browser.js +169 -68
  231. package/dist/server/builder-browser.js.map +1 -1
  232. package/dist/server/credential-provider.d.ts +2 -2
  233. package/dist/server/credential-provider.d.ts.map +1 -1
  234. package/dist/server/credential-provider.js +31 -12
  235. package/dist/server/credential-provider.js.map +1 -1
  236. package/dist/server/framework-request-handler.d.ts.map +1 -1
  237. package/dist/server/framework-request-handler.js +31 -0
  238. package/dist/server/framework-request-handler.js.map +1 -1
  239. package/dist/server/google-oauth.d.ts.map +1 -1
  240. package/dist/server/google-oauth.js +10 -3
  241. package/dist/server/google-oauth.js.map +1 -1
  242. package/dist/server/google-realtime-session.d.ts.map +1 -1
  243. package/dist/server/google-realtime-session.js +19 -6
  244. package/dist/server/google-realtime-session.js.map +1 -1
  245. package/dist/server/index.d.ts +2 -0
  246. package/dist/server/index.d.ts.map +1 -1
  247. package/dist/server/index.js +2 -0
  248. package/dist/server/index.js.map +1 -1
  249. package/dist/server/onboarding-html.d.ts.map +1 -1
  250. package/dist/server/onboarding-html.js +45 -6
  251. package/dist/server/onboarding-html.js.map +1 -1
  252. package/dist/server/request-context.d.ts +17 -0
  253. package/dist/server/request-context.d.ts.map +1 -1
  254. package/dist/server/request-context.js +40 -1
  255. package/dist/server/request-context.js.map +1 -1
  256. package/dist/server/sentry-plugin.d.ts +11 -0
  257. package/dist/server/sentry-plugin.d.ts.map +1 -0
  258. package/dist/server/sentry-plugin.js +116 -0
  259. package/dist/server/sentry-plugin.js.map +1 -0
  260. package/dist/server/sentry.d.ts +92 -0
  261. package/dist/server/sentry.d.ts.map +1 -0
  262. package/dist/server/sentry.js +287 -0
  263. package/dist/server/sentry.js.map +1 -0
  264. package/dist/server/transcribe-voice.d.ts +2 -4
  265. package/dist/server/transcribe-voice.d.ts.map +1 -1
  266. package/dist/server/transcribe-voice.js +4 -16
  267. package/dist/server/transcribe-voice.js.map +1 -1
  268. package/dist/server/voice-providers-status.d.ts.map +1 -1
  269. package/dist/server/voice-providers-status.js +19 -35
  270. package/dist/server/voice-providers-status.js.map +1 -1
  271. package/dist/styles/agent-native.css +15 -0
  272. package/docs/content/cloneable-saas.md +7 -9
  273. package/docs/content/deployment.md +6 -2
  274. package/docs/content/dispatch.md +1 -1
  275. package/docs/content/extensions.md +177 -142
  276. package/docs/content/faq.md +2 -2
  277. package/docs/content/getting-started.md +13 -11
  278. package/docs/content/multi-app-workspace.md +2 -2
  279. package/docs/content/observability.md +47 -0
  280. package/docs/content/pure-agent-apps.md +1 -1
  281. package/docs/content/template-clips.md +3 -3
  282. package/docs/content/template-design.md +3 -3
  283. package/docs/content/template-dispatch.md +1 -1
  284. package/docs/content/template-forms.md +1 -1
  285. package/docs/content/template-mail.md +1 -1
  286. package/docs/content/what-is-agent-native.md +4 -4
  287. package/docs/content/workspace.md +1 -1
  288. package/package.json +2 -1
@@ -1,230 +1,265 @@
1
1
  ---
2
2
  title: "Extensions"
3
- description: "Lightweight interactive appsdashboards, widgets, calculators, monitors that the agent creates for you instantly, without changing your app's code."
3
+ description: "Mini-apps your users build inside your template a custom KPI tile in Analytics, a meeting-prep checklist in Calendar, a contact CRM widget in Mail. No deploys, no code edits, no schema changes."
4
4
  ---
5
5
 
6
6
  # Extensions
7
7
 
8
- Extensions are lightweight interactive apps that live inside your agent-native app. Think dashboards, widgets, calculators, API monitors, data lookups — anything you'd otherwise build by hand.
8
+ Extensions are **mini-apps your users build inside your template**.
9
9
 
10
- The key difference from the rest of your app: **extensions don't require code changes.** The agent creates and updates them at runtime, they're stored in the database, and they're ready to use immediately. No deploys, no builds, no pull requests.
10
+ If you've used QuickBooks Online, you've seen the model: QBO ships a core accounting product, and users layer on small custom widgets — a custom report, a payroll calculator, a tax-rule checker — that live inside the same app and use the same data. Extensions are the agent-native version of that idea, except your users don't write any code. They describe what they want, and the agent builds it.
11
11
 
12
- ## Extensions vs. LLM tools {#extensions-vs-llm-tools}
12
+ The framing matters: an extension isn't a generic "do whatever you want" sandbox. It's a **mini-app that extends a specific template** — Mail, Analytics, Calendar, Clips, Design — and uses that template's actions and data. A Mail extension reads emails. An Analytics extension reads a dashboard's metrics. A Calendar extension acts on the open event. They feel like part of the host product because they _are_ part of the host product.
13
13
 
14
- The word "tools" gets used in two different ways in this codebase, so we use distinct names to keep them clear:
14
+ Three things make extensions work:
15
15
 
16
- - **Extensions** (this primitive) — sandboxed Alpine.js mini-apps, rendered inside an iframe. They have a UI the user can interact with, persistent storage, and the ability to call your app's actions and external APIs. The rest of this page is about extensions.
17
- - **LLM tools / agent tools** the function calls the agent makes during a turn (the things you define with `defineAction`, MCP tools, or that show up in `tools/list` / `tools/call`). These are not user-facing apps; they're the function-call surface area the model sees. When you read `tool: { description, parameters }` on an `ActionEntry`, "agent's tools", or "tool calls" elsewhere in these docs, that's the LLM-tools sense.
16
+ - **No code, no deploy.** The agent writes them and they're live in seconds. Stored in the database, not the repo.
17
+ - **Full access to the template's data.** Extensions can call the same actions the agent calls `list-emails` in Mail, `list-decks` in Slides, `list-recordings` in Clips so they have everything the host app has.
18
+ - **Built-in storage.** Each extension has its own per-user / per-org key-value store, so it can save state without you adding a new SQL table.
18
19
 
19
- Both senses can show up on the same page (extensions can _call_ agent actions, which the agent also sees as tools), so when in doubt: if it has a UI inside an iframe, it's an extension; if it's a function-call name on a model turn, it's an LLM tool.
20
+ ## A quick gallery {#gallery}
20
21
 
21
- ## Extensions vs. editing the app {#extensions-vs-code}
22
+ Real extensions people would actually build, grouped by the template they live in. Each one is one focused thing — not a Swiss-army knife.
22
23
 
23
- Your agent-native app has a full codebase — React components, routes, actions, styles. When the agent edits that code, it's changing the app itself. That's powerful, but it requires a build step and a deploy.
24
+ ### Mail
24
25
 
25
- Extensions are different:
26
+ A user is reading an email from `priya@acme.com`. What kind of widget would help right there?
26
27
 
27
- | | App code | Extensions |
28
- | --------------------- | --------------------------------------- | -------------------------------------------------- |
29
- | **Created by** | Developer or agent editing source files | Agent or user, instantly from chat |
30
- | **Stored in** | Git repository | Database |
31
- | **Requires a build** | Yes | No |
32
- | **Requires a deploy** | Yes | No |
33
- | **Scope** | Part of the app for all users | Private by default, shareable |
34
- | **Best for** | Core app features | Personal dashboards, utilities, quick integrations |
28
+ - **Contact notes** — a sticky-note pad pinned to whoever the user is emailing. Loads notes for that contact, lets the user jot more.
29
+ - **Recent threads with this person** — a small list of the last five threads with the open contact, separate from the inbox view.
30
+ - **CRM enrichment** pulls the contact's company size, last meeting date, or open deals from your CRM.
31
+ - **Meeting scheduler shortcut** turns "find a time next week" into a one-click "send these slots" widget.
35
32
 
36
- Use app code for features that are core to the product. Use extensions for everything else — one-off utilities, personal dashboards, quick integrations, monitors, and things you want to spin up in seconds.
33
+ Sketch Contact notes (saves a note tied to whoever you're emailing):
37
34
 
38
- ## When to build an extension vs. a template feature {#when-to-build}
35
+ ```html
36
+ <div
37
+ class="p-4"
38
+ x-data="{
39
+ contactEmail: window.slotContext?.contactEmail,
40
+ note: '',
41
+ async init() {
42
+ if (!this.contactEmail) return;
43
+ const saved = await extensionData.get('notes', this.contactEmail);
44
+ if (saved) this.note = JSON.parse(saved.data).text;
45
+ },
46
+ async save() {
47
+ await extensionData.set('notes', this.contactEmail, { text: this.note });
48
+ }
49
+ }"
50
+ >
51
+ <p class="text-xs text-muted-foreground mb-2" x-text="contactEmail"></p>
52
+ <textarea
53
+ x-model="note"
54
+ @blur="save()"
55
+ class="w-full rounded-md border bg-background p-2 text-sm"
56
+ rows="4"
57
+ placeholder="Notes about this contact..."
58
+ ></textarea>
59
+ </div>
60
+ ```
39
61
 
40
- A quick decision rubric:
62
+ ### Analytics
41
63
 
42
- **Build an extension when:**
64
+ A user is staring at a dashboard. What's the missing tile?
43
65
 
44
- - It's for one user or one team, not the whole product.
45
- - It's a quick utility, dashboard, or widget you want now, not next sprint.
46
- - No new database schema is needed (or per-extension key-value storage is enough).
47
- - You want to ship it inside a single chat turn, no deploy.
66
+ - **Custom KPI box** — a single big number for a metric that isn't a built-in panel. "Trials started this week," "MRR delta vs last month."
67
+ - **Goal tracker** — pulls a metric the user picks and shows progress against a target the user typed in.
68
+ - **Top customers leaderboard** joins a metric with a customer table, ranks the top 10.
48
69
 
49
- **Add a template feature when:**
70
+ Sketch Custom KPI box (calls one of the analytics template's `appAction` queries):
71
+
72
+ ```html
73
+ <div
74
+ class="p-4"
75
+ x-data="{
76
+ value: null,
77
+ async init() {
78
+ const result = await appAction('query-agent-native-analytics', {
79
+ metric: 'trials_started',
80
+ range: '7d'
81
+ });
82
+ this.value = result?.total ?? 0;
83
+ }
84
+ }"
85
+ >
86
+ <p class="text-xs uppercase tracking-wider text-muted-foreground">
87
+ Trials this week
88
+ </p>
89
+ <p class="text-3xl font-bold mt-1" x-text="value ?? '—'"></p>
90
+ </div>
91
+ ```
50
92
 
51
- - Every user of the template should get it.
52
- - It needs new SQL tables, migrations, or shared schema changes.
53
- - The UI is complex enough to warrant React components, routes, and proper testing.
54
- - It's part of the product surface — something you'd advertise on a landing page.
93
+ ### Calendar
55
94
 
56
- When in doubt, start as an extension. Promoting an extension to a template feature later is straightforward; rolling back a half-shipped product feature is not.
95
+ The user has an event open. What would help in that moment?
57
96
 
58
- ## Creating an extension {#creating}
97
+ - **Meeting prep checklist** — auto-loads agenda items, attendees, and prior thread summaries for the open event.
98
+ - **Travel time** — "you have 35 minutes until your next meeting at the Mission location."
99
+ - **Timezone helper** — shows the meeting time in every attendee's local time at a glance.
59
100
 
60
- ### From the sidebar
101
+ ### Clips
61
102
 
62
- Click the **+** button in the Extensions section of the sidebar. Describe what you want in plain language — "a dashboard that shows my open GitHub PRs" — and the agent builds it for you.
103
+ A user is reviewing a screen recording. What enhances that view?
63
104
 
64
- ### From chat
105
+ - **Action item extractor** — reads the clip transcript (the agent fetches it via `appAction`), lists the to-dos.
106
+ - **Auto-share** — one-click "post this clip's link to my #recordings Slack channel."
107
+ - **Highlight reel** — pulls the chapters the agent generated and turns them into a quick navigation menu.
65
108
 
66
- Just ask: "Create an extension that monitors our API health" or "Make me a calculator for shipping costs." The agent handles the rest.
109
+ ### Design
67
110
 
68
- ### Updating an extension
111
+ A user has a draft Alpine/Tailwind page open. What would smooth the prototyping loop?
69
112
 
70
- Ask the agent: "Update my PR dashboard to also show draft PRs" or "Add a dark mode toggle to the weather widget." The agent makes surgical edits without regenerating the whole thing.
113
+ - **Brand color swatch** palette pulled from the user's brand config, click to copy a color into the editor.
114
+ - **Asset picker** — lists images the user has uploaded, drops the URL on click.
115
+ - **Spacing inspector** — shows the gap/padding/margin tokens the active page uses, so the user can stay consistent.
71
116
 
72
- ## What extensions can do {#capabilities}
117
+ Pattern across all of these: extensions are about **the moment** the user is in inside the host template. The agent already knows which contact, which dashboard, which event, which clip — the extension uses that context.
73
118
 
74
- Extensions are fully capable despite being lightweight. They can:
119
+ ## How a user builds one {#building}
75
120
 
76
- - **Call external APIs** — GitHub, Stripe, weather services, any REST API. Requests go through a secure server-side proxy that keeps your API keys safe.
77
- - **Call your app's actions** — anything your agent can do, an extension can trigger.
78
- - **Query your app's database** — read and write data directly.
79
- - **Store their own data** — each extension has built-in persistent storage, no setup required. Save notes, preferences, cached results — whatever the extension needs.
80
- - **Call any endpoint in your app** — hit custom API routes, webhooks, or internal services.
121
+ The simple path:
81
122
 
82
- All of this works out of the box. No configuration, no new files, no schema changes.
123
+ 1. **Click "New Extension"** in the sidebar (or just ask in chat).
124
+ 2. **Describe what you want in one sentence.** "A sticky-note pad for the contact I'm emailing." "A KPI box for trials started this week."
125
+ 3. **The agent writes it and it appears in your Extensions list, ready to use.**
83
126
 
84
- ## Layout defaults {#layout}
127
+ No file to edit, no deploy. The agent picks the right helpers (`appAction`, `extensionData`, `extensionFetch`) and writes the Alpine.js HTML.
85
128
 
86
- Extensions render with modest canvas padding by default so simple widgets and dashboards do not hug the iframe edge. For full-bleed experiences such as maps, canvases, or custom editors, set `data-tool-layout="full-bleed"` or `data-tool-padding="none"` on the outermost element. (The `data-tool-*` attribute names are kept for backward compatibility `data-extension-layout` / `data-extension-padding` aliases are also accepted.)
129
+ If the extension needs an API key a CRM token, a weather API the agent tells you what to add and where to add it. Keys are stored encrypted and locked to specific domains.
87
130
 
88
- ## Persistent storage {#persistent-storage}
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.
89
132
 
90
- Every extension has access to a built-in key-value store via the `extensionData` helper (also exposed as `toolData` for backward compatibility). Data is automatically scoped per extension and per user — your data stays yours.
133
+ ## What an extension can do {#capabilities}
91
134
 
92
- When you ask the agent to "add persistence" or "remember state" in an extension, it uses this built-in storage. No database tables to create, no migrations to run.
135
+ Inside the iframe sandbox, every extension has these helpers on `window`:
93
136
 
94
- ### Scopes
137
+ | Helper | Purpose | Example |
138
+ | ------------------------------------------------ | ----------------------------------------------------- | ------------------------------------------------- |
139
+ | `appAction(name, params)` | Call any of the host template's actions | `appAction('list-emails', { view: 'inbox' })` |
140
+ | `appFetch(path, options)` | Call any app endpoint | `appFetch('/api/settings')` |
141
+ | `dbQuery(sql, args)` | Read from SQL (auto-scoped to the user) | `dbQuery('SELECT id, name FROM tools')` |
142
+ | `dbExec(sql, args)` | Write to SQL | `dbExec('INSERT INTO ...')` |
143
+ | `extensionFetch(url, options)` | Hit external APIs through a secure proxy with secrets | `extensionFetch('https://api.github.com/user')` |
144
+ | `extensionData.set(collection, id, data, opts?)` | Persist data per-extension (user / org scoping) | `extensionData.set('notes', id, { text: '...' })` |
145
+ | `extensionData.list(collection, opts?)` | List persisted items | `extensionData.list('notes', { scope: 'all' })` |
146
+ | `extensionData.get(collection, id, opts?)` | Get a single item | `extensionData.get('notes', 'note-1')` |
147
+ | `extensionData.remove(collection, id, opts?)` | Delete a persisted item | `extensionData.remove('notes', 'note-1')` |
95
148
 
96
- All `extensionData` methods accept an optional `{ scope }` option:
149
+ Two rules of thumb:
97
150
 
98
- - `'user'` (default) private to the current user.
99
- - `'org'` shared across the user's organization.
100
- - `'all'` — list/get only; returns both user-scoped and org-scoped items.
151
+ - **Prefer `appAction` over `dbQuery`.** Actions are the template's official surface — they handle access control, scoping, and validation for you. Reach for raw SQL only when no action fits.
152
+ - **Prefer `extensionData` over making new tables.** Each extension gets its own isolated key-value store. No schema, no migration. Set `{ scope: 'org' }` to share with the user's org, `'user'` (default) for private.
101
153
 
102
154
  ```html
103
155
  <script>
104
156
  // Private to me
105
- await extensionData.set('notes', 'note-1', { title: 'My Note' });
157
+ await extensionData.set('notes', 'note-1', { title: 'My note' });
106
158
 
107
159
  // Shared with my org
108
- await extensionData.set('notes', 'team-note', { title: 'Team Note' }, { scope: 'org' });
160
+ await extensionData.set('notes', 'team-note', { title: 'Team note' }, { scope: 'org' });
109
161
 
110
- // List my notes (default)
111
- const mine = await extensionData.list('notes');
112
-
113
- // List both mine and the org's
114
- const everything = await extensionData.list('notes', { scope: 'all' });
162
+ // List everything visible to me (mine + org)
163
+ const all = await extensionData.list('notes', { scope: 'all' });
115
164
  </script>
116
165
  ```
117
166
 
118
- > **Legacy alias.** The original helper was named `toolData`; both `toolData` and `extensionData` resolve to the same store and accept identical arguments. New extensions should use `extensionData`; existing code using `toolData` keeps working.
119
-
120
- ## API keys and secrets {#secrets}
121
-
122
- When an extension needs an API key (for GitHub, OpenAI, a weather service, etc.), the agent will tell you what's needed and where to get it. You add the key through the Settings UI in the agent sidebar.
123
-
124
- Keys are encrypted and stored securely. Each key is restricted to specific domains — a GitHub token can only be sent to `api.github.com`, never anywhere else.
125
-
126
- ### Secrets in extensions {#secrets-in-extensions}
127
-
128
- Extensions reference secrets in `extensionFetch()` calls (legacy alias: `toolFetch()`) using the `${keys.NAME}` template pattern. The proxy substitutes the encrypted value server-side; the actual key never reaches the browser.
167
+ External APIs go through `extensionFetch`, which proxies the call server-side and substitutes secrets via the `${keys.NAME}` template:
129
168
 
130
169
  ```html
131
170
  <script>
132
171
  const res = await extensionFetch('https://api.github.com/user', {
133
- headers: {
134
- Authorization: 'Bearer ${keys.GITHUB_TOKEN}',
135
- },
172
+ headers: { Authorization: 'Bearer ${keys.GITHUB_TOKEN}' },
136
173
  });
137
174
  </script>
138
175
  ```
139
176
 
140
- When an extension needs a one-off key, the agent can register an ad-hoc secret via `POST /_agent-native/secrets/adhoc` with a `urlAllowlist` that pins which domains the secret may be sent to. A request to any other host is rejected before the proxy fires. Combined with SSRF and private-network protections, this means a leaked extension can't exfiltrate secrets to an attacker-controlled URL.
177
+ The actual key never reaches the browser. Each key is locked to an allowlist of domains, so a leaked extension can't exfiltrate it elsewhere.
141
178
 
142
- ## Sharing {#sharing}
179
+ ## Slots — putting an extension inside the host UI {#slots}
143
180
 
144
- Extensions are **private by default** only you can see and use an extension you create.
181
+ The gallery above describes _what_ an extension does. Slots describe _where_ it appears.
145
182
 
146
- You can share extensions with your team:
183
+ By default, an extension lives on its own page in the Extensions list — open it like a small app. That's fine for dashboards, calculators, and standalone widgets.
147
184
 
148
- - **Org-visible**everyone in your organization can use it.
149
- - **Per-user sharing** — grant access to specific people as viewers, editors, or admins.
185
+ But the most QBO-shaped use case is different: the user wants their widget pinned _inside_ the template's UI under the contact info in Mail's sidebar, in the corner of an Analytics dashboard, on the right side of a Calendar event. That's what **slots** are for.
150
186
 
151
- Shared extensions have their own URLs, so you can link to them directly.
187
+ A slot is a named widget area a template ships:
152
188
 
153
- Under the hood, extensions use the same ownable-resource model as the rest of the framework — `ownableColumns()` on the `extensions` Drizzle export (physical SQL table: `tools`) and a standard `createSharesTable()` for grants (physical table: `tool_shares`, exported as `extensionShares`). That means extensions plug into the same share dialog, access checks, and audit surfaces as documents, decks, dashboards, and any other shareable resource. See [Security](/docs/security) for the full access model.
189
+ | Template | Example slot | Where it shows up |
190
+ | ------------- | ------------------------------ | -------------------------------------------- |
191
+ | **Mail** | `mail.contact-sidebar.bottom` | Below the contact info on every email thread |
192
+ | **Analytics** | `analytics.dashboard.tiles` | Alongside the dashboard's built-in panels |
193
+ | **Calendar** | `calendar.event-detail.bottom` | Below the open event |
194
+ | **Clips** | `clips.right-panel.tabs` | A new tab in the clip review panel |
154
195
 
155
- ## Security {#security}
196
+ When an extension is **installed into a slot**, the host pushes the relevant context — the contact's email, the dashboard id, the event id — into the iframe. The extension reads `window.slotContext` to know what the user is looking at.
197
+
198
+ ### A concrete example
156
199
 
157
- Extensions run in a secure sandbox:
200
+ Imagine the contact-notes extension from the gallery. On its own, it's a standalone widget. To make it appear inside the Mail contact sidebar:
158
201
 
159
- - **Isolated** extensions can't access your app's cookies, session, or page content.
160
- - **API keys stay server-side** secrets are injected by the server, never exposed to the browser.
161
- - **Domain-restricted secrets** each API key can only be sent to its approved domains.
162
- - **Private network protection** — extensions can't reach internal/private network addresses.
163
- - **Authentication required** — only logged-in users can use extensions.
202
+ 1. Build the extension once. Use `window.slotContext.contactEmail` so it knows which contact the user is on.
203
+ 2. Tell it the slot it can fill: `add-extension-slot-target { extensionId, slotId: "mail.contact-sidebar.bottom" }`.
204
+ 3. Install it: `install-extension { extensionId, slotId: "mail.contact-sidebar.bottom" }`.
164
205
 
165
- ## Extension API reference {#api-reference}
206
+ The next time you open an email thread, your sticky-note pad is right under the contact info — populated with notes for the person you're emailing. Switch to a different thread, the notes for _that_ contact load. Same extension, different context, no rewrites.
166
207
 
167
- Every extension runs inside a sandboxed iframe with the following helpers injected on `window`. They are the complete surface area anything else an extension needs has to go through one of these.
208
+ In practice you don't run those three commands by hand. Just say "pin this widget to my contact sidebar" and the agent handles target + install for you.
168
209
 
169
- | Helper | Purpose | Example |
170
- | ------------------------------------------------ | -------------------------- | ------------------------------------------------- |
171
- | `extensionData.set(collection, id, data, opts?)` | Persist data per-extension | `extensionData.set('notes', id, { text: '...' })` |
172
- | `extensionData.list(collection, opts?)` | List persisted items | `extensionData.list('notes', { scope: 'all' })` |
173
- | `extensionData.get(collection, id, opts?)` | Get a single item | `extensionData.get('notes', 'note-1')` |
174
- | `extensionData.remove(collection, id, opts?)` | Delete persisted item | `extensionData.remove('notes', 'note-1')` |
175
- | `appAction(name, params)` | Call any app action | `appAction('list-emails', { view: 'inbox' })` |
176
- | `dbQuery(sql, args)` | Read from SQL | `dbQuery('SELECT * FROM tools')` |
177
- | `dbExec(sql, args)` | Write to SQL | `dbExec('INSERT INTO ...')` |
178
- | `appFetch(path, options)` | Call any app endpoint | `appFetch('/api/settings')` |
179
- | `extensionFetch(url, options)` | External API via proxy | `extensionFetch('https://api.github.com/...')` |
210
+ > **Slots are an _added_ capability, not a prerequisite.** Plenty of useful extensions never get installed into a slot — they live happily on their own page. Reach for slots when the widget needs to be _next to_ what the user is looking at in the host template.
180
211
 
181
- `appAction` is the preferred way to trigger app behavior it routes through the same actions the agent and the frontend use, so authorization and access scoping happen automatically. Drop down to `dbQuery`/`dbExec` only when there's no action that fits.
212
+ For deeper detail on slots how to declare them in your template, how the context contract works, how installs are scoped see the `extension-points` skill.
182
213
 
183
- > **Legacy aliases and physical names.** `toolData` and `toolFetch` are kept as aliases for `extensionData` and `extensionFetch`. The physical SQL tables (`tools`, `tool_data`, `tool_shares`) and the `tool_id` foreign-key column also keep their original names — only the public Drizzle/TypeScript exports (`extensions`, `extensionData`, `extensionShares`) and the iframe globals were renamed.
214
+ ## Sharing {#sharing}
215
+
216
+ Extensions are private to the user who created them by default. To share:
217
+
218
+ - **Org-visible** — everyone in the org can see and use it.
219
+ - **Per-user grants** — invite specific people as viewer / editor / admin.
184
220
 
185
- ### Routes {#routes}
221
+ Shared extensions have their own URLs and plug into the same share dialog as documents, decks, and dashboards. Slot installs are always personal — sharing an extension means others _can_ install it; it doesn't auto-pin it to their UI.
186
222
 
187
- The framework mounts the following endpoints under `/_agent-native/extensions/`. Extensions themselves rarely call these directly — they're useful when integrating extensions with external scripts or custom UI. The legacy `/_agent-native/tools/*` paths still resolve and are kept for backward compatibility.
223
+ ## Extensions vs. editing the app code {#vs-app-code}
188
224
 
189
- | Method | Path | Purpose |
190
- | ------ | -------------------------------------- | ------------------------------------------------- |
191
- | GET | `/_agent-native/extensions` | List extensions (filtered by ownership + sharing) |
192
- | POST | `/_agent-native/extensions` | Create an extension |
193
- | GET | `/_agent-native/extensions/:id` | Get a single extension |
194
- | PUT | `/_agent-native/extensions/:id` | Update (supports `patches` for diffing) |
195
- | DELETE | `/_agent-native/extensions/:id` | Delete an extension |
196
- | GET | `/_agent-native/extensions/:id/render` | Render the iframe HTML |
197
- | POST | `/_agent-native/extensions/proxy` | Authenticated proxy with secret injection |
225
+ The framework lets the agent edit the app's source code directly — components, routes, styles. So when should you reach for an extension instead?
198
226
 
199
- ### Agent actions {#agent-actions}
227
+ | | Extension | App code edit |
228
+ | --------------------- | ------------------------------------------------- | ------------------------------------ |
229
+ | **Created by** | Agent (or user) at runtime | Agent editing source files |
230
+ | **Stored in** | The database | The git repository |
231
+ | **Requires a build** | No | Yes |
232
+ | **Requires a deploy** | No | Yes |
233
+ | **Scope** | One user (or shared with org) | The entire product, every user |
234
+ | **Best for** | Personal widgets, custom KPIs, per-team utilities | Core features that ship to all users |
200
235
 
201
- The agent uses three actions to manage extensions on your behalf:
236
+ Rule of thumb: **if it's for one user or one team, it's an extension.** If every user of the template should get it, ship it as a real feature.
237
+
238
+ ## Security {#security}
202
239
 
203
- | Action | What it does |
204
- | ------------------ | ------------------------------------------------------------------------- |
205
- | `create-extension` | Create a new extension (name, description, Alpine.js HTML content) |
206
- | `update-extension` | Update an extension — use `patches` array for find/replace diffs |
207
- | `navigate` | Navigate to `--view=extensions` or `--view=extensions --extensionId=<id>` |
240
+ Extensions run in a sandboxed iframe:
208
241
 
209
- > **Legacy action names.** `create-tool` and `update-tool` continue to work as aliases for `create-extension` and `update-extension`. New code should use the `*-extension` names.
242
+ - **Isolated** from the parent app's cookies, session, and DOM.
243
+ - **Server-side secret injection** via the `${keys.NAME}` template — the actual key value never reaches the browser.
244
+ - **Domain-locked secrets** — each key is bound to a URL allowlist; the proxy refuses requests to other hosts.
245
+ - **Private-network protection** — extensions can't reach internal addresses.
246
+ - **Auth required** — extensions only run for logged-in users, and `dbQuery` / `dbExec` calls are auto-scoped.
210
247
 
211
- ## Examples {#examples}
248
+ ## A few things to know about naming {#naming-back-compat}
212
249
 
213
- Here are some things people build as extensions:
250
+ If you're poking around the SQL or the source, you'll see a mix of "extension" and "tool" names. Quick decoder:
214
251
 
215
- - **GitHub PR dashboard** see open PRs, review status, and CI checks at a glance
216
- - **API health monitor** check if your services are up with a single click
217
- - **Weather widget** quick weather lookup for any city
218
- - **Stripe payment lookup** search recent payments and refunds
219
- - **Database explorer** — browse and query your app's data
220
- - **Shipping cost calculator** — compute rates based on weight and destination
221
- - **Meeting notes summarizer** — paste notes, get action items
222
- - **Social media scheduler** — draft and schedule posts across platforms
252
+ - The user-facing primitive used to be called "Tools." It's now **Extensions**.
253
+ - The physical SQL tables (`tools`, `tool_data`, `tool_shares`, `tool_slots`, `tool_slot_installs`) keep their original names — renaming a table is a destructive migration, and the framework doesn't ship destructive migrations.
254
+ - The Drizzle / TypeScript exports use the new names: `extensions`, `extensionData`, `extensionShares`, `extensionSlots`, `extensionSlotInstalls`.
255
+ - Inside an extension's iframe, the canonical helpers are `extensionFetch` and `extensionData`. The legacy names `toolFetch` and `toolData` still resolve, so older extension HTML keeps working.
223
256
 
224
- To create any of these, just describe what you want in the agent chat.
257
+ You also won't see this in normal use, but the agent has a third related concept called "LLM tools" — the function-call surface area on a model turn (defined via `defineAction`, MCP, etc.). Those are the function-calling primitive, not the user-facing widgets. When this page says "extension," it means the user-facing widget; when other docs say "tool" alongside `defineAction`, that's the LLM concept.
225
258
 
226
259
  ## What's next
227
260
 
228
- - [**Actions**](/docs/actions) — the operations that extensions (and the agent) can call
229
- - [**Workspace**](/docs/workspace) — the broader workspace system extensions live alongside
230
- - [**Security**](/docs/security) — the framework's data scoping and access control
261
+ - [**Templates**](/docs/cloneable-saas) — the host apps extensions extend
262
+ - [**Actions**](/docs/actions) — the operations an extension calls via `appAction`
263
+ - [**Sharing & Privacy**](/docs/sharing) — how extension visibility, org sharing, and per-user grants work
264
+ - [**Onboarding & API Keys**](/docs/onboarding) — how secrets surface in the settings UI
265
+ - [**Security**](/docs/security) — the framework's data scoping and access model
@@ -17,7 +17,7 @@ Agent-native is a framework for building apps where the AI agent and the UI are
17
17
 
18
18
  Anyone who wants to ship an AI-powered product without spending a year building the boring parts. That includes:
19
19
 
20
- - **Founders and PMs** who want to fork a working SaaS and make it their own — see [Cloneable SaaS](/docs/cloneable-saas).
20
+ - **Founders and PMs** who want to fork a working SaaS and make it their own — see [Templates](/docs/cloneable-saas).
21
21
  - **Operators** who want a [pure-agent app](/docs/pure-agent-apps) — an agent that does work in the background with a minimal management UI.
22
22
  - **Developers** building agent-driven products from scratch and want auth, multi-tenancy, real-time sync, and an architecture that won't break when AI is the primary user.
23
23
 
@@ -71,7 +71,7 @@ The framework ships with production-ready templates you can use as daily drivers
71
71
  - **[Forms](/templates/forms)** — form builder (like Typeform)
72
72
  - **[Dispatch](/templates/dispatch)** — workspace control plane: shared secrets, integrations, jobs
73
73
 
74
- Each template is a complete app with UI, agent actions, database schema, and AI instructions. See [Cloneable SaaS](/docs/cloneable-saas) for the full picture, or all [Templates](/templates).
74
+ Each template is a complete app with UI, agent actions, database schema, and AI instructions. See [Templates](/docs/cloneable-saas) for the full picture, or all [Templates](/templates).
75
75
 
76
76
  ### Can I customize templates? {#can-i-customize-templates}
77
77
 
@@ -12,7 +12,7 @@ By the end of this page, you'll have a working app — Mail, Calendar, Forms, or
12
12
  There are two ways to use agent-native, depending on how hands-on you want to be:
13
13
 
14
14
  - **You want to use a hosted version.** Try a template right now at [agent-native.com/templates](/templates). Each template is a live, hosted app — you sign in, start using it, and the agent is already there. No install, no setup. You can stop reading this page and head straight to the [template gallery](/templates).
15
- - **You want to run locally or customize it.** You'll clone a template, run it on your machine, and shape it however you want — branding, features, integrations. The rest of this page is for you. You'll need [Node.js](https://nodejs.org) and [pnpm](https://pnpm.io) installed.
15
+ - **You want to run locally or customize it.** You'll clone a template, run it on your machine, and shape it however you want — branding, features, integrations. The rest of this page is for you. You'll need [Node.js 24 LTS](https://nodejs.org) and [pnpm](https://pnpm.io) installed.
16
16
 
17
17
  Not sure which path? If you've never written code, the hosted version is for you. If you have a developer or AI coding tool ready, the local path gives you total control.
18
18
 
@@ -26,9 +26,9 @@ cd my-platform
26
26
  pnpm install && pnpm dev
27
27
  ```
28
28
 
29
- The `create` command shows a multi-select picker — pick one template or several (Mail + Calendar + Forms, for example) and they all scaffold into one workspace sharing auth, brand, and agent config.
29
+ The `create` command defaults to a workspace monorepo. It shows a multi-select picker — pick one template or several (Mail + Calendar + Forms, for example) and they all scaffold into one workspace sharing auth, brand, and agent config. If you want one app directory instead, pass `--standalone`.
30
30
 
31
- Open the URL the dev server prints (usually `http://localhost:3000`).
31
+ Open the URL the dev server prints. Workspace apps use app-specific ports, often `http://localhost:8080` or another 808x port; standalone apps usually use `http://localhost:3000`.
32
32
 
33
33
  ## What just happened? {#what-just-happened}
34
34
 
@@ -40,24 +40,26 @@ You now have a real, full-featured app running on your machine. Open it in the b
40
40
 
41
41
  That parity between agent and UI is the whole point — see [What Is Agent-Native?](/docs/what-is-agent-native) for the bigger picture.
42
42
 
43
- ## What's next {#whats-next}
43
+ ## Try one concrete next step {#first-next-step}
44
44
 
45
45
  From here, use any AI coding tool (Claude Code, Cursor, Windsurf, Builder.io) to customize the app. The agent instructions in `AGENTS.md` are already set up so any tool understands the codebase.
46
46
 
47
- Common next steps:
47
+ Good first moves:
48
48
 
49
- - **Add another app to the same workspace** — run `agent-native add-app` from inside the workspace folder. See [Multi-App Workspace](/docs/multi-app-workspace) for sharing auth, components, and credentials across apps.
49
+ - **Ask the built-in agent what it sees** — open the agent panel and type "what app am I looking at, and what can you do here?" This verifies the app, UI state, and agent loop are all talking to each other.
50
+ - **Make a tiny customization** — ask your coding tool to rename the app, change the first screen copy, or add one field to a form. It will read `AGENTS.md` for the framework conventions.
51
+ - **Add another app to the same workspace** — use `npx @agent-native/core add-app` from inside the workspace folder. The command starts at `npx`.
50
52
  - **Single app instead of a monorepo?** Pass `--standalone` when creating: `npx @agent-native/core create my-app --standalone --template mail`.
51
- - **Build a brand-new template from scratch** — see [Creating Templates](/docs/creating-templates) for the full Vite, Tailwind, and TypeScript setup.
52
- - **Understand the architecture** — see [Key Concepts](/docs/key-concepts) for how SQL, actions, polling sync, and context awareness fit together.
53
53
 
54
- ## What's next {#next-steps}
54
+ ## Next docs to read {#next-docs}
55
55
 
56
- Once your app is running, the most common next steps are:
56
+ Once your app is running, the most useful follow-ups are:
57
57
 
58
58
  - **Connect Slack or email** so you can message your agent from anywhere — see [Messaging](/docs/messaging).
59
59
  - **Set up Dispatch as your central inbox** to triage messages and orchestrate across multiple apps — see [Dispatch](/docs/dispatch).
60
60
  - **Customize via Workspace** — edit instructions, skills, memory, and connect MCP servers per user — see [Workspace](/docs/workspace).
61
+ - **Troubleshoot common setup questions** — see the [FAQ](/docs/faq).
62
+ - **Understand the architecture** — see [Key Concepts](/docs/key-concepts) for how SQL, actions, polling sync, and context awareness fit together.
61
63
 
62
64
  ## Templates {#templates}
63
65
 
@@ -77,7 +79,7 @@ Each template is a complete app with UI, agent actions, database schema, and AI
77
79
  | [Dispatch](/docs/template-dispatch) | Workspace control plane — secrets, routing, jobs |
78
80
  | [Starter](/docs/template-starter) | Minimal scaffold — build from scratch |
79
81
 
80
- Browse the [template gallery](/templates) for live demos, or see [Cloneable SaaS](/docs/cloneable-saas) for the full list and the clone → customize → deploy flow.
82
+ Browse the [template gallery](/templates) for live demos, or see [Templates](/docs/cloneable-saas) for the full list and the clone → customize → deploy flow.
81
83
 
82
84
  ## Project structure {#project-structure}
83
85
 
@@ -86,13 +86,13 @@ Every app already knows how to log in, share the same database, and load the wor
86
86
  From anywhere inside the workspace:
87
87
 
88
88
  ```bash
89
- agent-native add-app
89
+ npx @agent-native/core add-app
90
90
  ```
91
91
 
92
92
  The CLI shows the template picker again with apps you've already installed filtered out. Pick one or more and they get scaffolded under `apps/`. Non-interactive variant:
93
93
 
94
94
  ```bash
95
- agent-native add-app crm --template content
95
+ npx @agent-native/core add-app crm --template content
96
96
  ```
97
97
 
98
98
  Any first-party template works as a workspace app — the CLI runs a small **workspacify** transform on the template that adds the shared package as a dep and resolves `workspace:*` references. No parallel "workspace-app" scaffold to maintain.
@@ -182,3 +182,50 @@ await putSetting("observability-config", {
182
182
  ```
183
183
 
184
184
  The framework emits `gen_ai.*` semantic convention spans compatible with the OpenTelemetry GenAI spec.
185
+
186
+ ## Error Reporting (Sentry)
187
+
188
+ Server-side errors that escape Nitro route handlers are reported to Sentry when a DSN is configured. Without it the SDK silently no-ops, so it's safe to leave the env vars unset in dev. Three independent Sentry projects cover the framework:
189
+
190
+ | Surface | SDK | Env var | Notes |
191
+ | ------------------ | ----------------- | ------------------------ | --------------------------------------------------------------------- |
192
+ | Browser / SPA | `@sentry/browser` | `VITE_SENTRY_CLIENT_DSN` | Captures unhandled errors and route-change breadcrumbs in the client. |
193
+ | Nitro server | `@sentry/node` | `SENTRY_SERVER_DSN` | Captures 5xx responses and Nitro lifecycle errors. Per-request user. |
194
+ | `agent-native` CLI | `@sentry/node` | _hardcoded_ | Crash reports from the published CLI binary; not user-configurable. |
195
+
196
+ ### Server-side configuration
197
+
198
+ Set `SENTRY_SERVER_DSN` in the deploy environment (Netlify dashboard, Cloudflare secrets, etc.). The framework auto-mounts a Nitro plugin that:
199
+
200
+ 1. Calls `Sentry.init` once at startup (idempotent — safe to call from multiple plugins).
201
+ 2. Resolves the user via `getSession(event)` on every API/framework request and attaches `id` / `email` / `username` plus an `orgId` tag to Sentry's per-request isolation scope. Static-asset paths are skipped to avoid extra DB hits.
202
+ 3. Captures every framework-route 5xx with searchable `route`, `method`, and `userAgent` tags.
203
+
204
+ Optional knobs:
205
+
206
+ - `SENTRY_SERVER_TRACES_SAMPLE_RATE` (float `0`–`1`) — opt in to performance tracing. Defaults to `0` (errors only). Invalid values clamp to `0`.
207
+ - `AGENT_NATIVE_RELEASE` — overrides the `release` tag. Defaults to `agent-native-server@<core-version>`.
208
+
209
+ ### Templates
210
+
211
+ Every template inherits this automatically — there's nothing to import. Templates that want custom behavior (extra tags, different DSN per template, hard-disable Sentry) can override by exporting their own plugin from `server/plugins/sentry.ts`:
212
+
213
+ ```ts
214
+ // server/plugins/sentry.ts
215
+ import { createSentryPlugin } from "@agent-native/core/server";
216
+ export default createSentryPlugin();
217
+ ```
218
+
219
+ The CLI's hardcoded DSN is intentional — the published binary needs to phone home crashes regardless of which environment runs it. The server module never hardcodes a DSN because it runs inside customer environments where operators decide whether errors should reach Sentry at all.
220
+
221
+ ### Privacy & PII
222
+
223
+ Both server and CLI initialize with `sendDefaultPii: false` and a `beforeSend` hook that strips:
224
+
225
+ - `request.headers.authorization`, `cookie`, `set-cookie`, `proxy-authorization`
226
+ - `request.cookies`
227
+ - `user.ip_address` (auto-collected without consent)
228
+ - `contexts.runtime_env` (process env snapshot)
229
+ - Any event whose top-level exception type is `ValidationError` (treated as expected user-input rejection, not a bug).
230
+
231
+ Identity fields explicitly set via `setUser({ id, email, username })` are preserved.
@@ -33,7 +33,7 @@ Pick the pure-agent pattern when:
33
33
  - **The domain is one-shot.** Research bot, summary generator, report writer. There's no persistent object that needs a list view.
34
34
  - **You're prototyping.** Ship the agent now; add a richer UI later if it turns out users actually want one.
35
35
 
36
- If your product is built around persistent objects users browse, pivot, and share — emails, events, documents, charts — pick a [cloneable SaaS](/docs/cloneable-saas) template instead. Those have full UIs _plus_ the agent.
36
+ If your product is built around persistent objects users browse, pivot, and share — emails, events, documents, charts — pick a [template](/docs/cloneable-saas) instead. Those have full UIs _plus_ the agent.
37
37
 
38
38
  ## What ships in the box {#minimum-ui}
39
39