@agent-native/core 0.127.3 → 0.128.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 (410) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +80 -0
  3. package/corpus/core/README.md +5 -26
  4. package/corpus/core/docs/content/actions.mdx +47 -4
  5. package/corpus/core/docs/content/native-chat-ui.mdx +7 -0
  6. package/corpus/core/docs/content/organizations-teams-permissions.mdx +109 -3
  7. package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
  8. package/corpus/core/docs/content/toolkit-org-team.mdx +72 -12
  9. package/corpus/core/package.json +1 -1
  10. package/corpus/core/src/a2a/artifact-response.ts +36 -29
  11. package/corpus/core/src/action.ts +83 -2
  12. package/corpus/core/src/chat-threads/store.ts +48 -43
  13. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
  14. package/corpus/core/src/client/AgentPanel.tsx +26 -6
  15. package/corpus/core/src/client/AssistantChat.tsx +63 -7
  16. package/corpus/core/src/client/DefaultSpinner.tsx +29 -0
  17. package/corpus/core/src/client/org/TeamPage.tsx +161 -6
  18. package/corpus/core/src/client/org/hooks.ts +67 -0
  19. package/corpus/core/src/client/org/index.ts +9 -0
  20. package/corpus/core/src/client/transcription/use-live-transcription.ts +62 -10
  21. package/corpus/core/src/db/client.ts +42 -3
  22. package/corpus/core/src/db/ensure-additive-columns.ts +60 -33
  23. package/corpus/core/src/deploy/build.ts +31 -2
  24. package/corpus/core/src/mcp-client/routes.ts +10 -1
  25. package/corpus/core/src/org/app-roles-handlers.ts +152 -0
  26. package/corpus/core/src/org/app-roles.ts +355 -0
  27. package/corpus/core/src/org/index.ts +27 -1
  28. package/corpus/core/src/org/migrations.ts +22 -0
  29. package/corpus/core/src/org/plugin.ts +27 -0
  30. package/corpus/core/src/org/schema.ts +15 -0
  31. package/corpus/core/src/scripts/docs/search.ts +17 -0
  32. package/corpus/core/src/scripts/docs/source-search.ts +10 -0
  33. package/corpus/core/src/server/agent-chat/script-entries.ts +3 -0
  34. package/corpus/core/src/server/agent-chat-plugin.ts +53 -52
  35. package/corpus/core/src/server/core-routes-plugin.ts +6 -1
  36. package/corpus/core/src/server/framework-request-handler.ts +44 -6
  37. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
  38. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  39. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +31 -0
  40. package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  42. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  43. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  46. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -0
  47. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +31 -0
  48. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +4 -0
  49. package/corpus/templates/analytics/actions/data-source-status.ts +21 -12
  50. package/corpus/templates/analytics/app/global.css +7 -7
  51. package/corpus/templates/analytics/app/i18n-data.ts +30 -0
  52. package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -1
  53. package/corpus/templates/analytics/app/pages/DataSources.tsx +54 -10
  54. package/corpus/templates/analytics/changelog/2026-07-28-analytics-pages-load-reliably-with-large-dashboard-workspaces.md +6 -0
  55. package/corpus/templates/analytics/changelog/2026-07-28-dashboard-loading-shimmer-now-flows-smoothly-in-one-directi.md +6 -0
  56. package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +5 -4
  57. package/corpus/templates/analytics/server/plugins/agent-chat.ts +54 -42
  58. package/corpus/templates/analytics/server/plugins/db.ts +1 -18
  59. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -0
  60. package/corpus/templates/assets/.agents/skills/security/SKILL.md +31 -0
  61. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +4 -0
  62. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -0
  63. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +7 -0
  64. package/corpus/templates/brain/.agents/skills/security/SKILL.md +31 -0
  65. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +4 -0
  66. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -0
  67. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +31 -0
  68. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +4 -0
  69. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  70. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  71. package/corpus/templates/chat/.agents/skills/security/SKILL.md +31 -0
  72. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  73. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -0
  74. package/corpus/templates/clips/.agents/skills/security/SKILL.md +31 -0
  75. package/corpus/templates/clips/actions/request-transcript.ts +77 -11
  76. package/corpus/templates/clips/actions/save-browser-transcript.ts +28 -7
  77. package/corpus/templates/clips/app/routes/record.tsx +11 -3
  78. package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-save-a-truncated-transcript-as-.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-stop-transcribing-partway-throu.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-28-desktop-full-screen-clips-now-get-an-instant-local-transcrip.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-28-long-transcriptions-no-longer-show-a-false-transcription-sto.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-28-restarting-for-an-update-now-installs-the-newest-release-ins.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-28-the-meeting-recording-pill-now-anchors-to-the-right-edge-of-.md +6 -0
  84. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +31 -2
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +114 -13
  86. package/corpus/templates/clips/desktop/src/lib/updater.ts +12 -4
  87. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +40 -15
  88. package/corpus/templates/clips/desktop/src/styles.css +10 -7
  89. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -14
  90. package/corpus/templates/clips/shared/transcript-status.ts +10 -0
  91. package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -0
  92. package/corpus/templates/content/.agents/skills/security/SKILL.md +31 -0
  93. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +4 -0
  94. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +4 -0
  95. package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -0
  96. package/corpus/templates/design/.agents/skills/security/SKILL.md +31 -0
  97. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +4 -0
  98. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +46 -3
  99. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +7 -5
  100. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
  101. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -4
  102. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
  103. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +10 -4
  104. package/corpus/templates/design/app/lib/design-ui-events.ts +5 -0
  105. package/corpus/templates/design/app/root.tsx +18 -1
  106. package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +6 -0
  107. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -0
  108. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +31 -0
  109. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +4 -0
  110. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -0
  111. package/corpus/templates/forms/.agents/skills/security/SKILL.md +31 -0
  112. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +4 -0
  113. package/corpus/templates/macros/.agents/skills/security/SKILL.md +31 -0
  114. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +4 -0
  115. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -0
  116. package/corpus/templates/mail/.agents/skills/security/SKILL.md +31 -0
  117. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +4 -0
  118. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -0
  119. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +7 -0
  120. package/corpus/templates/plan/.agents/skills/security/SKILL.md +31 -0
  121. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +4 -0
  122. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -0
  123. package/corpus/templates/slides/.agents/skills/security/SKILL.md +31 -0
  124. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +4 -0
  125. package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -0
  126. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +7 -0
  127. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +31 -0
  128. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +4 -0
  129. package/dist/a2a/artifact-response.d.ts.map +1 -1
  130. package/dist/a2a/artifact-response.js +30 -29
  131. package/dist/a2a/artifact-response.js.map +1 -1
  132. package/dist/action.d.ts +36 -0
  133. package/dist/action.d.ts.map +1 -1
  134. package/dist/action.js +37 -2
  135. package/dist/action.js.map +1 -1
  136. package/dist/chat-threads/store.d.ts +12 -0
  137. package/dist/chat-threads/store.d.ts.map +1 -1
  138. package/dist/chat-threads/store.js +48 -42
  139. package/dist/chat-threads/store.js.map +1 -1
  140. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
  141. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
  142. package/dist/cli/skills-content/design-visual-edit-skill.js +46 -3
  143. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
  144. package/dist/client/AgentPanel.d.ts +3 -1
  145. package/dist/client/AgentPanel.d.ts.map +1 -1
  146. package/dist/client/AgentPanel.js +11 -9
  147. package/dist/client/AgentPanel.js.map +1 -1
  148. package/dist/client/AssistantChat.d.ts.map +1 -1
  149. package/dist/client/AssistantChat.js +57 -6
  150. package/dist/client/AssistantChat.js.map +1 -1
  151. package/dist/client/DefaultSpinner.d.ts +7 -0
  152. package/dist/client/DefaultSpinner.d.ts.map +1 -1
  153. package/dist/client/DefaultSpinner.js +25 -1
  154. package/dist/client/DefaultSpinner.js.map +1 -1
  155. package/dist/client/org/TeamPage.d.ts +13 -1
  156. package/dist/client/org/TeamPage.d.ts.map +1 -1
  157. package/dist/client/org/TeamPage.js +41 -11
  158. package/dist/client/org/TeamPage.js.map +1 -1
  159. package/dist/client/org/hooks.d.ts +37 -0
  160. package/dist/client/org/hooks.d.ts.map +1 -1
  161. package/dist/client/org/hooks.js +37 -0
  162. package/dist/client/org/hooks.js.map +1 -1
  163. package/dist/client/org/index.d.ts +3 -2
  164. package/dist/client/org/index.d.ts.map +1 -1
  165. package/dist/client/org/index.js +1 -1
  166. package/dist/client/org/index.js.map +1 -1
  167. package/dist/client/transcription/use-live-transcription.d.ts +8 -0
  168. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  169. package/dist/client/transcription/use-live-transcription.js +38 -11
  170. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  171. package/dist/collab/routes.d.ts +2 -2
  172. package/dist/db/client.d.ts +12 -0
  173. package/dist/db/client.d.ts.map +1 -1
  174. package/dist/db/client.js +40 -3
  175. package/dist/db/client.js.map +1 -1
  176. package/dist/db/ensure-additive-columns.d.ts.map +1 -1
  177. package/dist/db/ensure-additive-columns.js +54 -32
  178. package/dist/db/ensure-additive-columns.js.map +1 -1
  179. package/dist/deploy/build.d.ts +1 -0
  180. package/dist/deploy/build.d.ts.map +1 -1
  181. package/dist/deploy/build.js +23 -2
  182. package/dist/deploy/build.js.map +1 -1
  183. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  184. package/dist/mcp-client/routes.d.ts +3 -1
  185. package/dist/mcp-client/routes.d.ts.map +1 -1
  186. package/dist/mcp-client/routes.js +8 -2
  187. package/dist/mcp-client/routes.js.map +1 -1
  188. package/dist/notifications/routes.d.ts +1 -1
  189. package/dist/org/app-roles-handlers.d.ts +27 -0
  190. package/dist/org/app-roles-handlers.d.ts.map +1 -0
  191. package/dist/org/app-roles-handlers.js +125 -0
  192. package/dist/org/app-roles-handlers.js.map +1 -0
  193. package/dist/org/app-roles.d.ts +136 -0
  194. package/dist/org/app-roles.d.ts.map +1 -0
  195. package/dist/org/app-roles.js +216 -0
  196. package/dist/org/app-roles.js.map +1 -0
  197. package/dist/org/index.d.ts +4 -1
  198. package/dist/org/index.d.ts.map +1 -1
  199. package/dist/org/index.js +3 -1
  200. package/dist/org/index.js.map +1 -1
  201. package/dist/org/migrations.d.ts.map +1 -1
  202. package/dist/org/migrations.js +22 -0
  203. package/dist/org/migrations.js.map +1 -1
  204. package/dist/org/plugin.d.ts +2 -0
  205. package/dist/org/plugin.d.ts.map +1 -1
  206. package/dist/org/plugin.js +20 -0
  207. package/dist/org/plugin.js.map +1 -1
  208. package/dist/org/schema.d.ts +143 -0
  209. package/dist/org/schema.d.ts.map +1 -1
  210. package/dist/org/schema.js +14 -0
  211. package/dist/org/schema.js.map +1 -1
  212. package/dist/progress/routes.d.ts +1 -1
  213. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  214. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  215. package/dist/scripts/docs/search.d.ts.map +1 -1
  216. package/dist/scripts/docs/search.js +15 -0
  217. package/dist/scripts/docs/search.js.map +1 -1
  218. package/dist/scripts/docs/source-search.d.ts +7 -0
  219. package/dist/scripts/docs/source-search.d.ts.map +1 -1
  220. package/dist/scripts/docs/source-search.js +9 -0
  221. package/dist/scripts/docs/source-search.js.map +1 -1
  222. package/dist/secrets/routes.d.ts +9 -9
  223. package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
  224. package/dist/server/agent-chat/script-entries.js +3 -0
  225. package/dist/server/agent-chat/script-entries.js.map +1 -1
  226. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  227. package/dist/server/agent-chat-plugin.js +46 -48
  228. package/dist/server/agent-chat-plugin.js.map +1 -1
  229. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  230. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  231. package/dist/server/core-routes-plugin.js +6 -1
  232. package/dist/server/core-routes-plugin.js.map +1 -1
  233. package/dist/server/framework-request-handler.d.ts.map +1 -1
  234. package/dist/server/framework-request-handler.js +42 -6
  235. package/dist/server/framework-request-handler.js.map +1 -1
  236. package/dist/server/realtime-token.d.ts +1 -1
  237. package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  238. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  239. package/dist/templates/chat/.agents/skills/security/SKILL.md +31 -0
  240. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  241. package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -0
  242. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  243. package/dist/templates/default/.agents/skills/security/SKILL.md +31 -0
  244. package/dist/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  245. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  246. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  247. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  248. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  249. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  250. package/docs/content/actions.mdx +47 -4
  251. package/docs/content/native-chat-ui.mdx +7 -0
  252. package/docs/content/organizations-teams-permissions.mdx +109 -3
  253. package/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
  254. package/docs/content/toolkit-org-team.mdx +72 -12
  255. package/package.json +1 -1
  256. package/src/a2a/artifact-response.ts +36 -29
  257. package/src/action.ts +83 -2
  258. package/src/chat-threads/store.ts +48 -43
  259. package/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
  260. package/src/client/AgentPanel.tsx +26 -6
  261. package/src/client/AssistantChat.tsx +63 -7
  262. package/src/client/DefaultSpinner.tsx +29 -0
  263. package/src/client/org/TeamPage.tsx +161 -6
  264. package/src/client/org/hooks.ts +67 -0
  265. package/src/client/org/index.ts +9 -0
  266. package/src/client/transcription/use-live-transcription.ts +62 -10
  267. package/src/db/client.ts +42 -3
  268. package/src/db/ensure-additive-columns.ts +60 -33
  269. package/src/deploy/build.ts +31 -2
  270. package/src/mcp-client/routes.ts +10 -1
  271. package/src/org/app-roles-handlers.ts +152 -0
  272. package/src/org/app-roles.ts +355 -0
  273. package/src/org/index.ts +27 -1
  274. package/src/org/migrations.ts +22 -0
  275. package/src/org/plugin.ts +27 -0
  276. package/src/org/schema.ts +15 -0
  277. package/src/scripts/docs/search.ts +17 -0
  278. package/src/scripts/docs/source-search.ts +10 -0
  279. package/src/server/agent-chat/script-entries.ts +3 -0
  280. package/src/server/agent-chat-plugin.ts +53 -52
  281. package/src/server/core-routes-plugin.ts +6 -1
  282. package/src/server/framework-request-handler.ts +44 -6
  283. package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -0
  284. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
  285. package/src/templates/chat/.agents/skills/security/SKILL.md +31 -0
  286. package/src/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
  287. package/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
  288. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
  289. package/src/templates/default/.agents/skills/security/SKILL.md +31 -0
  290. package/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
  291. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
  292. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
  293. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
  294. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
  295. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
  296. package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +0 -530
  297. package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +0 -191
  298. package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +0 -115
  299. package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
  300. package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +0 -89
  301. package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +0 -221
  302. package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +0 -220
  303. package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +0 -263
  304. package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +0 -169
  305. package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +0 -174
  306. package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +0 -232
  307. package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +0 -282
  308. package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +0 -119
  309. package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +0 -123
  310. package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +0 -122
  311. package/corpus/core/src/templates/chat/.env.example +0 -5
  312. package/corpus/core/src/templates/chat/.ignore +0 -0
  313. package/corpus/core/src/templates/chat/.oxfmtrc.json +0 -8
  314. package/corpus/core/src/templates/chat/AGENTS.md +0 -77
  315. package/corpus/core/src/templates/chat/CHANGELOG.md +0 -10
  316. package/corpus/core/src/templates/chat/DEVELOPING.md +0 -185
  317. package/corpus/core/src/templates/chat/README.md +0 -32
  318. package/corpus/core/src/templates/chat/_gitignore +0 -46
  319. package/corpus/core/src/templates/chat/actions/hello.ts +0 -13
  320. package/corpus/core/src/templates/chat/actions/navigate.ts +0 -41
  321. package/corpus/core/src/templates/chat/actions/run.ts +0 -2
  322. package/corpus/core/src/templates/chat/actions/view-screen.ts +0 -31
  323. package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +0 -60
  324. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +0 -188
  325. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -505
  326. package/corpus/core/src/templates/chat/app/components/ui/button.tsx +0 -1
  327. package/corpus/core/src/templates/chat/app/components/ui/card.tsx +0 -1
  328. package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +0 -1
  329. package/corpus/core/src/templates/chat/app/components/ui/input.tsx +0 -1
  330. package/corpus/core/src/templates/chat/app/components/ui/label.tsx +0 -1
  331. package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +0 -1
  332. package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +0 -17
  333. package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +0 -1
  334. package/corpus/core/src/templates/chat/app/design-system.ts +0 -3
  335. package/corpus/core/src/templates/chat/app/entry.client.tsx +0 -22
  336. package/corpus/core/src/templates/chat/app/entry.server.tsx +0 -10
  337. package/corpus/core/src/templates/chat/app/global.css +0 -93
  338. package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +0 -93
  339. package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +0 -68
  340. package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +0 -71
  341. package/corpus/core/src/templates/chat/app/i18n/en-US.ts +0 -70
  342. package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +0 -71
  343. package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +0 -71
  344. package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +0 -69
  345. package/corpus/core/src/templates/chat/app/i18n/index.ts +0 -34
  346. package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +0 -70
  347. package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +0 -70
  348. package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +0 -71
  349. package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +0 -66
  350. package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +0 -66
  351. package/corpus/core/src/templates/chat/app/i18n-data.ts +0 -556
  352. package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +0 -49
  353. package/corpus/core/src/templates/chat/app/lib/app-config.ts +0 -11
  354. package/corpus/core/src/templates/chat/app/lib/tab-id.ts +0 -1
  355. package/corpus/core/src/templates/chat/app/lib/utils.ts +0 -1
  356. package/corpus/core/src/templates/chat/app/root.tsx +0 -173
  357. package/corpus/core/src/templates/chat/app/routes/_index.tsx +0 -94
  358. package/corpus/core/src/templates/chat/app/routes/agent.tsx +0 -24
  359. package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +0 -1
  360. package/corpus/core/src/templates/chat/app/routes/database.tsx +0 -17
  361. package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +0 -2
  362. package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +0 -11
  363. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +0 -11
  364. package/corpus/core/src/templates/chat/app/routes/extensions.tsx +0 -5
  365. package/corpus/core/src/templates/chat/app/routes/observability.tsx +0 -19
  366. package/corpus/core/src/templates/chat/app/routes/settings.tsx +0 -89
  367. package/corpus/core/src/templates/chat/app/routes/team.tsx +0 -11
  368. package/corpus/core/src/templates/chat/app/routes.ts +0 -4
  369. package/corpus/core/src/templates/chat/app/vite-env.d.ts +0 -6
  370. package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
  371. package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
  372. package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
  373. package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +0 -6
  374. package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
  375. package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +0 -5
  376. package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +0 -6
  377. package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +0 -6
  378. package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +0 -6
  379. package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +0 -6
  380. package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +0 -6
  381. package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +0 -6
  382. package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +0 -6
  383. package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
  384. package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +0 -6
  385. package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +0 -6
  386. package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +0 -6
  387. package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +0 -6
  388. package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +0 -6
  389. package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +0 -6
  390. package/corpus/core/src/templates/chat/components.json +0 -20
  391. package/corpus/core/src/templates/chat/learnings.defaults.md +0 -5
  392. package/corpus/core/src/templates/chat/netlify.toml +0 -11
  393. package/corpus/core/src/templates/chat/package.json +0 -92
  394. package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +0 -10
  395. package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +0 -10
  396. package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +0 -21
  397. package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +0 -21
  398. package/corpus/core/src/templates/chat/public/favicon.svg +0 -1
  399. package/corpus/core/src/templates/chat/public/icon-180.svg +0 -1
  400. package/corpus/core/src/templates/chat/public/icon-192.svg +0 -1
  401. package/corpus/core/src/templates/chat/public/icon-512.svg +0 -1
  402. package/corpus/core/src/templates/chat/public/manifest.json +0 -21
  403. package/corpus/core/src/templates/chat/react-router.config.ts +0 -7
  404. package/corpus/core/src/templates/chat/server/middleware/auth.ts +0 -15
  405. package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +0 -21
  406. package/corpus/core/src/templates/chat/server/plugins/auth.ts +0 -17
  407. package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +0 -5
  408. package/corpus/core/src/templates/chat/ssr-entry.ts +0 -15
  409. package/corpus/core/src/templates/chat/tsconfig.json +0 -21
  410. package/corpus/core/src/templates/chat/vite.config.ts +0 -19
@@ -502,21 +502,9 @@ export function createAgentChatPlugin(
502
502
  const { awaitBootstrap } = await import("./framework-request-handler.js");
503
503
  await awaitBootstrap(nitroApp);
504
504
 
505
- // Reap phantom runs left over from the previous process (HMR restart,
506
- // process crash, isolate eviction). Any run whose heartbeat is already
507
- // stale by startup time had a dead producer; mark it errored so the
508
- // next /runs/active check returns a terminal status and reconnecting
509
- // clients don't spin on "Thinking...". Runs owned by OTHER live
510
- // isolates are protected by their fresh heartbeats.
511
- try {
512
- const { reapAllStaleRuns } = await import("../agent/run-store.js");
513
- const reaped = await reapAllStaleRuns();
514
- if (reaped > 0) {
515
- console.log(`[agent-chat] reaped ${reaped} stale run(s) on startup`);
516
- }
517
- } catch {
518
- // Best effort — don't block plugin init if SQL isn't ready yet.
519
- }
505
+ // Never make route readiness wait on an org-global stale-run sweep.
506
+ // `/runs/active` reaps the requested run on demand, and the periodic
507
+ // recovery sweep below handles abandoned runs with no connected client.
520
508
 
521
509
  const env = process.env.NODE_ENV;
522
510
  // AGENT_MODE=production forces production agent constraints even in dev
@@ -561,44 +549,47 @@ export function createAgentChatPlugin(
561
549
  extensionTools: options?.extensionTools,
562
550
  });
563
551
 
564
- // Initialize MCP client. Merges file/env config + auto-detected binaries
565
- // + any remote servers users have added through the settings UI (persisted
566
- // in the settings table, scanned across all scopes so we never drop
567
- // another user's entries). Graceful-degrade: any failure yields zero MCP
568
- // tools and agent-chat keeps working as before.
569
- let mcpConfig = await buildMergedConfig().catch((err) => {
570
- console.warn(
571
- `[mcp-client] buildMergedConfig failed: ${err?.message ?? err}`,
572
- );
573
- return null;
574
- });
575
- if (!mcpConfig) {
576
- const fileOrEnv = loadMcpConfig() ?? autoDetectMcpConfig();
577
- mcpConfig = fileOrEnv;
578
- if (mcpConfig?.source) {
579
- console.log(
580
- `[mcp-client] loaded config from ${mcpConfig.source} (${Object.keys(mcpConfig.servers).length} server(s))`,
552
+ // Route readiness must not wait on settings scans, remote hub fetches, or
553
+ // third-party MCP handshakes. Build the action surface against an empty
554
+ // manager, then hydrate it after every live action registry has subscribed
555
+ // to manager changes.
556
+ const mcpManager = new McpClientManager(null);
557
+ setGlobalMcpManager(mcpManager);
558
+ const mcpActionEntries: Record<string, ActionEntry> = {};
559
+ let mcpInitializationPromise: Promise<void> | null = null;
560
+ const initializeMcpManager = async (): Promise<void> => {
561
+ let mcpConfig = await buildMergedConfig().catch((err) => {
562
+ console.warn(
563
+ `[mcp-client] buildMergedConfig failed: ${err?.message ?? err}`,
581
564
  );
582
- } else if (process.env.DEBUG) {
565
+ return null;
566
+ });
567
+ if (!mcpConfig) {
568
+ mcpConfig = loadMcpConfig() ?? autoDetectMcpConfig();
569
+ if (mcpConfig?.source) {
570
+ console.log(
571
+ `[mcp-client] loaded config from ${mcpConfig.source} (${Object.keys(mcpConfig.servers).length} server(s))`,
572
+ );
573
+ } else if (process.env.DEBUG) {
574
+ console.log(
575
+ "[mcp-client] no configured MCP servers — skipping MCP tools",
576
+ );
577
+ }
578
+ } else if (mcpConfig.source) {
583
579
  console.log(
584
- "[mcp-client] no configured MCP servers skipping MCP tools",
580
+ `[mcp-client] merged config (${Object.keys(mcpConfig.servers).length} server(s), source: ${mcpConfig.source})`,
585
581
  );
586
582
  }
587
- } else if (mcpConfig.source) {
588
- console.log(
589
- `[mcp-client] merged config (${Object.keys(mcpConfig.servers).length} server(s), source: ${mcpConfig.source})`,
590
- );
591
- }
592
- const mcpManager = new McpClientManager(mcpConfig);
593
- try {
594
- await mcpManager.start();
595
- } catch (err: any) {
596
- console.warn(
597
- `[mcp-client] start() failed: ${err?.message ?? err}. Continuing without MCP tools.`,
598
- );
599
- }
600
- setGlobalMcpManager(mcpManager);
601
- const mcpActionEntries = mcpToolsToActionEntries(mcpManager);
583
+ try {
584
+ await mcpManager.reconfigure(mcpConfig);
585
+ } catch (err: any) {
586
+ console.warn(
587
+ `[mcp-client] initialization failed: ${err?.message ?? err}. Continuing without MCP tools.`,
588
+ );
589
+ } finally {
590
+ startMcpConfigRefresh(mcpManager);
591
+ }
592
+ };
602
593
  const getJobMcpActionEntries = (
603
594
  job?: RecurringJobContext,
604
595
  ): Record<string, ActionEntry> => {
@@ -619,8 +610,11 @@ export function createAgentChatPlugin(
619
610
  // Mount status + management routes so the settings UI can list / add /
620
611
  // remove remote MCP servers and hot-reload the running manager.
621
612
  mountMcpStatusRoute(nitroApp, mcpManager);
622
- mountMcpServersRoutes(nitroApp, mcpManager);
623
- startMcpConfigRefresh(mcpManager);
613
+ mountMcpServersRoutes(nitroApp, mcpManager, {
614
+ // Serialize an unusually early settings mutation behind the initial
615
+ // config snapshot so stale startup data cannot overwrite the write.
616
+ waitUntilReady: () => mcpInitializationPromise ?? Promise.resolve(),
617
+ });
624
618
  // Hub-serve: expose org-scope servers to other agent-native apps in the
625
619
  // workspace when `AGENT_NATIVE_MCP_HUB_TOKEN` is set (dispatch, by
626
620
  // convention). Gated by the env var so mounting is a no-op otherwise.
@@ -5694,6 +5688,13 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5694
5688
  }
5695
5689
  }
5696
5690
 
5691
+ mcpInitializationPromise = initializeMcpManager().catch((err) => {
5692
+ console.warn(
5693
+ `[mcp-client] deferred initialization failed: ${err?.message ?? err}`,
5694
+ );
5695
+ });
5696
+ void mcpInitializationPromise;
5697
+
5697
5698
  // ─── Agent Teams orphan sweep ─────────────────────────────────────
5698
5699
  // Re-fires stuck/queued dispatches when the browser is closed and the
5699
5700
  // RunsTray's per-user reconciliation never triggers. Runs every 2 minutes
@@ -6001,7 +6002,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
6001
6002
  });
6002
6003
  if (process.env.DEBUG)
6003
6004
  console.log("[triggers] Trigger dispatcher initialized");
6004
- } catch (err) {
6005
+ } catch {
6005
6006
  // Triggers module not available — skip silently
6006
6007
  }
6007
6008
  }
@@ -4251,8 +4251,13 @@ export function createCoreRoutesPlugin(
4251
4251
  }
4252
4252
  resolveInit();
4253
4253
  } catch (error) {
4254
+ // Do NOT rethrow. Nitro invokes plugins as `try { plugin(app) } catch`,
4255
+ // which cannot catch an async rejection, so rethrowing here surfaces as
4256
+ // an unhandledRejection: Node exits, the serverless container dies, and
4257
+ // every in-flight request on it returns a bare 502. `rejectInit` already
4258
+ // routes this failure to the readiness gate, which answers the affected
4259
+ // paths with a retryable 503 instead.
4254
4260
  rejectInit(error);
4255
- throw error;
4256
4261
  }
4257
4262
  };
4258
4263
  }
@@ -335,11 +335,39 @@ export async function awaitBootstrap(nitroApp: any): Promise<void> {
335
335
  async function awaitFrameworkRoutesReadyForRequest(
336
336
  nitroApp: any,
337
337
  reqPath: string,
338
- ): Promise<void> {
339
- if (!nitroApp) return;
340
- const bootstrapPromise = nitroApp[BOOTSTRAP_PROMISE_KEY];
341
- if (bootstrapPromise) await bootstrapPromise;
342
- await awaitPluginsReady(nitroApp, reqPath);
338
+ ): Promise<boolean> {
339
+ if (!nitroApp) return true;
340
+ let timer: ReturnType<typeof setTimeout> | undefined;
341
+ try {
342
+ return await Promise.race([
343
+ (async () => {
344
+ const bootstrapPromise = nitroApp[BOOTSTRAP_PROMISE_KEY];
345
+ if (bootstrapPromise) await bootstrapPromise;
346
+ await awaitPluginsReady(nitroApp, reqPath);
347
+ return true;
348
+ })(),
349
+ new Promise<boolean>((resolve) => {
350
+ timer = setTimeout(() => resolve(false), frameworkReadyDeadlineMs());
351
+ }),
352
+ ]);
353
+ } finally {
354
+ if (timer) clearTimeout(timer);
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Cap on how long a request may be held waiting for framework routes.
360
+ *
361
+ * Holding past the platform's own request wall is pure loss: the serverless
362
+ * gateway kills the invocation and the client gets a bare 502/504 it cannot
363
+ * act on. Releasing first lets the placeholder answer with a retryable 503.
364
+ * Keep this BELOW the shortest deployment target's request wall (Netlify
365
+ * synchronous functions cut off around 40s regardless of a higher configured
366
+ * `timeout`).
367
+ */
368
+ function frameworkReadyDeadlineMs(): number {
369
+ const raw = Number(process.env.AGENT_NATIVE_ROUTE_READY_TIMEOUT_MS);
370
+ return Number.isFinite(raw) && raw > 0 ? raw : 25_000;
343
371
  }
344
372
 
345
373
  /**
@@ -417,7 +445,17 @@ function installPluginReadyPlaceholders(
417
445
  const eventAny = event as any;
418
446
  const reqPath =
419
447
  eventAny.context?._mountedPathname ?? event.url?.pathname ?? path;
420
- await awaitFrameworkRoutesReadyForRequest(nitroApp, reqPath);
448
+ const ready = await awaitFrameworkRoutesReadyForRequest(
449
+ nitroApp,
450
+ reqPath,
451
+ );
452
+ if (!ready) {
453
+ // Boot is still running and we are out of budget. Answer now, while
454
+ // the gateway is still listening, rather than being killed mid-wait.
455
+ setResponseStatus(event, 503);
456
+ setResponseHeader(event, "retry-after", "5");
457
+ return { error: "agent-native routes are still initializing" };
458
+ }
421
459
  // If this plugin's async init failed, its real route was never
422
460
  // registered. Return a retryable 503 instead of releasing into a bare
423
461
  // 404 (external MCP clients can't recover from a 404; a 503 is at least
@@ -305,6 +305,38 @@ export default defineAction({
305
305
 
306
306
  On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
307
307
 
308
+ ### Authorization (`authorize`)
309
+
310
+ `authorize` decides whether the caller may run the action at all. It wraps
311
+ `run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
312
+ hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
313
+ agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
314
+ to ask a human to bless one call a permitted caller is already allowed to make.
315
+
316
+ ```ts
317
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
318
+
319
+ export default defineAction({
320
+ description: "Archive a client roster.",
321
+ schema: z.object({ id: z.string() }),
322
+ authorize: coachAccess.requireAny("coach-admin"),
323
+ run: async (args) => {
324
+ /* ... */
325
+ },
326
+ });
327
+ ```
328
+
329
+ The wrappers compose as `validate input -> authorize -> run -> validate output
330
+ -> audit`: the gate sits inside input validation, so a guard reading `args` gets
331
+ the parsed, coerced value, and auditing is outermost, so denials are recorded.
332
+
333
+ A guard that throws denies with its own message; returning `false` denies
334
+ generically; anything else (including `undefined`) allows. A guarded action
335
+ needs a user identity, so an unattended CLI/cron caller with no user email is
336
+ denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
337
+ scope which rows a permitted caller may touch. See the `authentication` skill
338
+ for `defineAppRoles` and the `sharing` skill for row scoping.
339
+
308
340
  ### Human-in-the-Loop Approval (`needsApproval`)
309
341
 
310
342
  For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
@@ -179,8 +179,15 @@ If the feature stores **user-authored resources** (documents, dashboards, forms,
179
179
 
180
180
  TL;DR: spread `ownableColumns()` into the resource table, pair it with `createSharesTable(...)`, call `registerShareableResource(...)`, wrap list/read queries with `accessFilter`, guard writes with `assertAccess`, and drop `<ShareButton>` in the resource header. The `share-resource`, `unshare-resource`, `list-resource-shares`, and `set-resource-visibility` actions are auto-mounted framework-wide.
181
181
 
182
+ ## One more area — who inside the app may do it
183
+
184
+ If the feature is one **only some teammates should be able to perform inside this app** (an admin-only import, a settings reset), that is a per-app role — not a new organization, and not a share grant. See the `authentication` skill.
185
+
186
+ TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultRole })`, guard the action with `authorize: appAccess.requireAny("...")`, and render the picker with `<TeamPage appRoles={descriptor} />`. `defaultRole` is display only — it never satisfies a guard — and `authorize` gates the operation while `accessFilter` / `assertAccess` still scope the rows.
187
+
182
188
  ## Related Skills
183
189
 
190
+ - **authentication** — Per-app member roles (`defineAppRoles`) when only some teammates may use a feature
184
191
  - **sharing** — How to make a new resource ownable (private by default, share with users/orgs/public)
185
192
  - **context-awareness** — How to expose UI state to the agent (area 4 in detail)
186
193
  - **actions** — How to create actions with `defineAction` and the `http` option (area 2 in detail)
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
159
159
  private UI after the shell loads. See the `authentication` skill and
160
160
  `guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
161
161
 
162
+ **Authorization beyond "is there a session" — `authorize`.** The auth guard only
163
+ proves *someone* is signed in. To restrict an operation to some teammates, set
164
+ `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
+ dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
+ `needsApproval`, which is honoured only in the agent loop.
167
+
168
+ ```ts
169
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
170
+
171
+ export default defineAction({
172
+ description: "Archive a client roster.",
173
+ schema: z.object({ id: z.string() }),
174
+ authorize: coachAccess.requireAny("coach-admin"),
175
+ run: async (args) => {
176
+ /* ... */
177
+ },
178
+ });
179
+ ```
180
+
181
+ A guard that throws denies with its own message; returning `false` denies
182
+ generically; anything else (including `undefined`) allows. Guarded actions need
183
+ a user identity — an unattended CLI/cron caller with no user email is denied.
184
+
185
+ `authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
186
+ decides whether this caller may perform the operation at all; `accessFilter` /
187
+ `assertAccess` scope which rows a permitted caller may see or touch. A
188
+ restricted write action needs both. See the `authentication` skill for
189
+ `defineAppRoles` and the `actions` skill for the full surface.
190
+
162
191
  ## Human-in-the-Loop Approval for High-Consequence Actions
163
192
 
164
193
  For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
274
303
  - [ ] New env vars in `.env` only, not committed
275
304
  - [ ] New user-data tables have `owner_email` column
276
305
  - [ ] Custom routes call `getSession` and reject unauthenticated requests
306
+ - [ ] Actions only some teammates may run set `authorize` (in addition to any
307
+ `accessFilter` / `assertAccess` row scoping)
277
308
 
278
309
  ## Related Skills
279
310
 
@@ -305,6 +305,38 @@ export default defineAction({
305
305
 
306
306
  On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
307
307
 
308
+ ### Authorization (`authorize`)
309
+
310
+ `authorize` decides whether the caller may run the action at all. It wraps
311
+ `run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
312
+ hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
313
+ agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
314
+ to ask a human to bless one call a permitted caller is already allowed to make.
315
+
316
+ ```ts
317
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
318
+
319
+ export default defineAction({
320
+ description: "Archive a client roster.",
321
+ schema: z.object({ id: z.string() }),
322
+ authorize: coachAccess.requireAny("coach-admin"),
323
+ run: async (args) => {
324
+ /* ... */
325
+ },
326
+ });
327
+ ```
328
+
329
+ The wrappers compose as `validate input -> authorize -> run -> validate output
330
+ -> audit`: the gate sits inside input validation, so a guard reading `args` gets
331
+ the parsed, coerced value, and auditing is outermost, so denials are recorded.
332
+
333
+ A guard that throws denies with its own message; returning `false` denies
334
+ generically; anything else (including `undefined`) allows. A guarded action
335
+ needs a user identity, so an unattended CLI/cron caller with no user email is
336
+ denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
337
+ scope which rows a permitted caller may touch. See the `authentication` skill
338
+ for `defineAppRoles` and the `sharing` skill for row scoping.
339
+
308
340
  ### Human-in-the-Loop Approval (`needsApproval`)
309
341
 
310
342
  For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
@@ -305,6 +305,38 @@ export default defineAction({
305
305
 
306
306
  On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
307
307
 
308
+ ### Authorization (`authorize`)
309
+
310
+ `authorize` decides whether the caller may run the action at all. It wraps
311
+ `run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
312
+ hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
313
+ agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
314
+ to ask a human to bless one call a permitted caller is already allowed to make.
315
+
316
+ ```ts
317
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
318
+
319
+ export default defineAction({
320
+ description: "Archive a client roster.",
321
+ schema: z.object({ id: z.string() }),
322
+ authorize: coachAccess.requireAny("coach-admin"),
323
+ run: async (args) => {
324
+ /* ... */
325
+ },
326
+ });
327
+ ```
328
+
329
+ The wrappers compose as `validate input -> authorize -> run -> validate output
330
+ -> audit`: the gate sits inside input validation, so a guard reading `args` gets
331
+ the parsed, coerced value, and auditing is outermost, so denials are recorded.
332
+
333
+ A guard that throws denies with its own message; returning `false` denies
334
+ generically; anything else (including `undefined`) allows. A guarded action
335
+ needs a user identity, so an unattended CLI/cron caller with no user email is
336
+ denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
337
+ scope which rows a permitted caller may touch. See the `authentication` skill
338
+ for `defineAppRoles` and the `sharing` skill for row scoping.
339
+
308
340
  ### Human-in-the-Loop Approval (`needsApproval`)
309
341
 
310
342
  For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
@@ -179,8 +179,15 @@ If the feature stores **user-authored resources** (documents, dashboards, forms,
179
179
 
180
180
  TL;DR: spread `ownableColumns()` into the resource table, pair it with `createSharesTable(...)`, call `registerShareableResource(...)`, wrap list/read queries with `accessFilter`, guard writes with `assertAccess`, and drop `<ShareButton>` in the resource header. The `share-resource`, `unshare-resource`, `list-resource-shares`, and `set-resource-visibility` actions are auto-mounted framework-wide.
181
181
 
182
+ ## One more area — who inside the app may do it
183
+
184
+ If the feature is one **only some teammates should be able to perform inside this app** (an admin-only import, a settings reset), that is a per-app role — not a new organization, and not a share grant. See the `authentication` skill.
185
+
186
+ TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultRole })`, guard the action with `authorize: appAccess.requireAny("...")`, and render the picker with `<TeamPage appRoles={descriptor} />`. `defaultRole` is display only — it never satisfies a guard — and `authorize` gates the operation while `accessFilter` / `assertAccess` still scope the rows.
187
+
182
188
  ## Related Skills
183
189
 
190
+ - **authentication** — Per-app member roles (`defineAppRoles`) when only some teammates may use a feature
184
191
  - **sharing** — How to make a new resource ownable (private by default, share with users/orgs/public)
185
192
  - **context-awareness** — How to expose UI state to the agent (area 4 in detail)
186
193
  - **actions** — How to create actions with `defineAction` and the `http` option (area 2 in detail)
@@ -71,6 +71,46 @@ The auto-create path skips users with pending invites or a matching
71
71
  `AUTO_CREATE_DEFAULT_ORG=0` only for deployments that intentionally want manual
72
72
  org creation.
73
73
 
74
+ ### App-Specific Roles
75
+
76
+ When a request needs "only some teammates may do this **inside this app**", the
77
+ answer is per-app roles — **not** a second organization. App roles are an
78
+ overlay on the one org membership, never a second roster. Three role systems
79
+ coexist and never imply one another: the org role (`org_members.role`) says what
80
+ a person may do to the *team*, an app role says what they may do inside *one
81
+ app*, and a share role (`sharing` skill) says what they may do to *one row*. An
82
+ app `admin` is not an org admin, and org handlers never read app roles.
83
+
84
+ Declare the vocabulary once on the server and guard actions with it:
85
+
86
+ ```ts
87
+ import { defineAppRoles } from "@agent-native/core/org-team";
88
+
89
+ export const coachAccess = defineAppRoles({
90
+ appId: "coach",
91
+ roles: ["member", "coach-admin"] as const,
92
+ defaultRole: "member",
93
+ });
94
+
95
+ // in an action
96
+ authorize: coachAccess.requireAny("coach-admin"),
97
+ ```
98
+
99
+ Roles are an unordered set, not a ladder — declaration order carries no meaning,
100
+ and every guard names its accepted roles explicitly. `defaultRole` is **display
101
+ only**: `requireAny` matches an explicit assignment row and nothing else, so
102
+ "nobody assigned this person" never reads as "granted", and widening the default
103
+ cannot silently widen a guard. Org membership is a precondition, resolved in the
104
+ same statement as the assignment, so a leftover assignment for a removed member
105
+ can never authorize. Only org owners/admins may assign app roles; render the
106
+ picker with `<TeamPage appRoles={descriptor} />`.
107
+
108
+ `requireAny` validates at definition time — no roles, or a role outside the
109
+ declared vocabulary, throws when the module loads rather than surfacing as an
110
+ unexplained 403 later. When calling `resolve`/`assertAny` directly, note that an
111
+ explicit `userEmail: null` / `orgId: null` means "this run has no identity" and
112
+ does **not** fall back to the ambient request context; only `undefined` does.
113
+
74
114
  ### Stop And Confirm Before Creating Or Switching Organizations
75
115
 
76
116
  Vault credentials are scoped per organization and are **not** shared between
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
159
159
  private UI after the shell loads. See the `authentication` skill and
160
160
  `guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
161
161
 
162
+ **Authorization beyond "is there a session" — `authorize`.** The auth guard only
163
+ proves *someone* is signed in. To restrict an operation to some teammates, set
164
+ `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
+ dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
+ `needsApproval`, which is honoured only in the agent loop.
167
+
168
+ ```ts
169
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
170
+
171
+ export default defineAction({
172
+ description: "Archive a client roster.",
173
+ schema: z.object({ id: z.string() }),
174
+ authorize: coachAccess.requireAny("coach-admin"),
175
+ run: async (args) => {
176
+ /* ... */
177
+ },
178
+ });
179
+ ```
180
+
181
+ A guard that throws denies with its own message; returning `false` denies
182
+ generically; anything else (including `undefined`) allows. Guarded actions need
183
+ a user identity — an unattended CLI/cron caller with no user email is denied.
184
+
185
+ `authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
186
+ decides whether this caller may perform the operation at all; `accessFilter` /
187
+ `assertAccess` scope which rows a permitted caller may see or touch. A
188
+ restricted write action needs both. See the `authentication` skill for
189
+ `defineAppRoles` and the `actions` skill for the full surface.
190
+
162
191
  ## Human-in-the-Loop Approval for High-Consequence Actions
163
192
 
164
193
  For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
274
303
  - [ ] New env vars in `.env` only, not committed
275
304
  - [ ] New user-data tables have `owner_email` column
276
305
  - [ ] Custom routes call `getSession` and reject unauthenticated requests
306
+ - [ ] Actions only some teammates may run set `authorize` (in addition to any
307
+ `accessFilter` / `assertAccess` row scoping)
277
308
 
278
309
  ## Related Skills
279
310
 
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
34
34
  - **`editor`** — read + write.
35
35
  - **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
36
36
 
37
+ There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
38
+
37
39
  ### Anonymous public URLs stay separate
38
40
 
39
41
  Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
@@ -137,6 +139,8 @@ export default defineAction({
137
139
 
138
140
  For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
139
141
 
142
+ `authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
143
+
140
144
  ## Create actions must set owner
141
145
 
142
146
  When inserting a new row, fill `ownerEmail` and `orgId` from the request context:
@@ -305,6 +305,38 @@ export default defineAction({
305
305
 
306
306
  On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
307
307
 
308
+ ### Authorization (`authorize`)
309
+
310
+ `authorize` decides whether the caller may run the action at all. It wraps
311
+ `run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
312
+ hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
313
+ agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
314
+ to ask a human to bless one call a permitted caller is already allowed to make.
315
+
316
+ ```ts
317
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
318
+
319
+ export default defineAction({
320
+ description: "Archive a client roster.",
321
+ schema: z.object({ id: z.string() }),
322
+ authorize: coachAccess.requireAny("coach-admin"),
323
+ run: async (args) => {
324
+ /* ... */
325
+ },
326
+ });
327
+ ```
328
+
329
+ The wrappers compose as `validate input -> authorize -> run -> validate output
330
+ -> audit`: the gate sits inside input validation, so a guard reading `args` gets
331
+ the parsed, coerced value, and auditing is outermost, so denials are recorded.
332
+
333
+ A guard that throws denies with its own message; returning `false` denies
334
+ generically; anything else (including `undefined`) allows. A guarded action
335
+ needs a user identity, so an unattended CLI/cron caller with no user email is
336
+ denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
337
+ scope which rows a permitted caller may touch. See the `authentication` skill
338
+ for `defineAppRoles` and the `sharing` skill for row scoping.
339
+
308
340
  ### Human-in-the-Loop Approval (`needsApproval`)
309
341
 
310
342
  For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
159
159
  private UI after the shell loads. See the `authentication` skill and
160
160
  `guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
161
161
 
162
+ **Authorization beyond "is there a session" — `authorize`.** The auth guard only
163
+ proves *someone* is signed in. To restrict an operation to some teammates, set
164
+ `authorize` on the `defineAction`. It wraps `run`, so it applies at every
165
+ dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
166
+ `needsApproval`, which is honoured only in the agent loop.
167
+
168
+ ```ts
169
+ import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
170
+
171
+ export default defineAction({
172
+ description: "Archive a client roster.",
173
+ schema: z.object({ id: z.string() }),
174
+ authorize: coachAccess.requireAny("coach-admin"),
175
+ run: async (args) => {
176
+ /* ... */
177
+ },
178
+ });
179
+ ```
180
+
181
+ A guard that throws denies with its own message; returning `false` denies
182
+ generically; anything else (including `undefined`) allows. Guarded actions need
183
+ a user identity — an unattended CLI/cron caller with no user email is denied.
184
+
185
+ `authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
186
+ decides whether this caller may perform the operation at all; `accessFilter` /
187
+ `assertAccess` scope which rows a permitted caller may see or touch. A
188
+ restricted write action needs both. See the `authentication` skill for
189
+ `defineAppRoles` and the `actions` skill for the full surface.
190
+
162
191
  ## Human-in-the-Loop Approval for High-Consequence Actions
163
192
 
164
193
  For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
274
303
  - [ ] New env vars in `.env` only, not committed
275
304
  - [ ] New user-data tables have `owner_email` column
276
305
  - [ ] Custom routes call `getSession` and reject unauthenticated requests
306
+ - [ ] Actions only some teammates may run set `authorize` (in addition to any
307
+ `accessFilter` / `assertAccess` row scoping)
277
308
 
278
309
  ## Related Skills
279
310
 
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
34
34
  - **`editor`** — read + write.
35
35
  - **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
36
36
 
37
+ There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
38
+
37
39
  ### Anonymous public URLs stay separate
38
40
 
39
41
  Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
@@ -137,6 +139,8 @@ export default defineAction({
137
139
 
138
140
  For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
139
141
 
142
+ `authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
143
+
140
144
  ## Create actions must set owner
141
145
 
142
146
  When inserting a new row, fill `ownerEmail` and `orgId` from the request context: