@agent-native/core 0.114.0 → 0.114.2

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 (223) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +15 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/cli/create.ts +23 -0
  5. package/corpus/core/src/cli/skills.ts +24 -0
  6. package/corpus/core/src/client/build-compatibility.ts +77 -0
  7. package/corpus/core/src/client/route-chunk-recovery/index.ts +1 -0
  8. package/corpus/core/src/client/use-action.ts +32 -1
  9. package/corpus/core/src/deploy/build.ts +4 -1
  10. package/corpus/core/src/org/context.ts +56 -30
  11. package/corpus/core/src/server/action-routes.ts +52 -2
  12. package/corpus/core/src/server/auth-plugin.ts +9 -4
  13. package/corpus/core/src/server/better-auth-instance.ts +5 -1
  14. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  15. package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  16. package/corpus/core/src/templates/default/AGENTS.md +4 -1
  17. package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  18. package/corpus/core/src/templates/headless/AGENTS.md +5 -1
  19. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
  20. package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -1
  21. package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -1
  22. package/corpus/core/src/vite/client.ts +17 -0
  23. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  24. package/corpus/templates/analytics/AGENTS.md +5 -0
  25. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  26. package/corpus/templates/assets/AGENTS.md +5 -0
  27. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  28. package/corpus/templates/brain/AGENTS.md +5 -0
  29. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  30. package/corpus/templates/calendar/AGENTS.md +5 -0
  31. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  32. package/corpus/templates/chat/AGENTS.md +4 -1
  33. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  34. package/corpus/templates/clips/AGENTS.md +5 -0
  35. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  36. package/corpus/templates/content/AGENTS.md +7 -0
  37. package/corpus/templates/content/actions/_content-database-personal-view.ts +49 -5
  38. package/corpus/templates/content/actions/_content-document-access.ts +21 -0
  39. package/corpus/templates/content/actions/_content-favorites.ts +91 -0
  40. package/corpus/templates/content/actions/_content-files.ts +79 -23
  41. package/corpus/templates/content/actions/_content-sidebar-state.ts +24 -0
  42. package/corpus/templates/content/actions/_content-space-access.ts +15 -17
  43. package/corpus/templates/content/actions/_content-space-catalog-guards.ts +20 -0
  44. package/corpus/templates/content/actions/_content-spaces.ts +364 -167
  45. package/corpus/templates/content/actions/_database-source-utils.ts +8 -0
  46. package/corpus/templates/content/actions/_database-utils.ts +249 -15
  47. package/corpus/templates/content/actions/_delete-content-space.ts +84 -0
  48. package/corpus/templates/content/actions/_files-system-properties.ts +499 -0
  49. package/corpus/templates/content/actions/_local-file-documents.ts +0 -1
  50. package/corpus/templates/content/actions/_property-utils.ts +18 -9
  51. package/corpus/templates/content/actions/bind-content-database-source-field.ts +3 -0
  52. package/corpus/templates/content/actions/configure-document-property.ts +3 -0
  53. package/corpus/templates/content/actions/create-content-database.ts +2 -2
  54. package/corpus/templates/content/actions/create-content-space.ts +34 -0
  55. package/corpus/templates/content/actions/create-document.ts +4 -1
  56. package/corpus/templates/content/actions/delete-content-space.ts +19 -0
  57. package/corpus/templates/content/actions/delete-database-items.ts +28 -1
  58. package/corpus/templates/content/actions/delete-document-property.ts +3 -0
  59. package/corpus/templates/content/actions/delete-document.ts +39 -2
  60. package/corpus/templates/content/actions/duplicate-database-item.ts +6 -0
  61. package/corpus/templates/content/actions/duplicate-database-items.ts +6 -0
  62. package/corpus/templates/content/actions/duplicate-document-property.ts +3 -0
  63. package/corpus/templates/content/actions/get-content-database.ts +11 -2
  64. package/corpus/templates/content/actions/get-content-sidebar-state.ts +23 -0
  65. package/corpus/templates/content/actions/get-document.ts +32 -7
  66. package/corpus/templates/content/actions/import-content-source.ts +33 -1
  67. package/corpus/templates/content/actions/list-content-spaces.ts +34 -2
  68. package/corpus/templates/content/actions/list-documents.ts +39 -7
  69. package/corpus/templates/content/actions/reorder-document-property.ts +9 -0
  70. package/corpus/templates/content/actions/set-document-property.ts +41 -23
  71. package/corpus/templates/content/actions/share-local-file-document.ts +15 -0
  72. package/corpus/templates/content/actions/submit-content-database-form.ts +7 -0
  73. package/corpus/templates/content/actions/sync-local-folder-source.ts +14 -0
  74. package/corpus/templates/content/actions/update-content-database-view.ts +1 -0
  75. package/corpus/templates/content/actions/update-content-sidebar-state.ts +27 -0
  76. package/corpus/templates/content/actions/update-document.ts +158 -66
  77. package/corpus/templates/content/app/components/EmptyState.tsx +4 -57
  78. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +8 -1
  79. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +519 -178
  80. package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +39 -0
  81. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
  82. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +266 -7
  83. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +430 -152
  84. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +467 -66
  85. package/corpus/templates/content/app/components/editor/database/view-config.ts +9 -3
  86. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +720 -196
  87. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +173 -1
  88. package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +1 -1
  89. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +91 -16
  90. package/corpus/templates/content/app/entry.client.tsx +5 -1
  91. package/corpus/templates/content/app/hooks/use-content-database.ts +84 -3
  92. package/corpus/templates/content/app/hooks/use-content-spaces.ts +60 -2
  93. package/corpus/templates/content/app/hooks/use-create-page.ts +30 -0
  94. package/corpus/templates/content/app/hooks/use-documents.ts +270 -19
  95. package/corpus/templates/content/app/i18n-data.ts +243 -20
  96. package/corpus/templates/content/app/lib/local-folder-picker-safety.ts +54 -0
  97. package/corpus/templates/content/app/lib/local-folder-picker-support.ts +18 -0
  98. package/corpus/templates/content/app/routes/_app.favorites.tsx +30 -0
  99. package/corpus/templates/content/app/routes/_app.local-files.tsx +18 -6
  100. package/corpus/templates/content/changelog/2026-07-17-workspace-files-now-stay-in-a-loading-state-until-automatic-.md +6 -0
  101. package/corpus/templates/content/changelog/2026-07-17-workspace-switching-now-opens-the-selected-files-database-pr.md +6 -0
  102. package/corpus/templates/content/changelog/2026-07-17-workspaces-now-expand-above-their-own-files-list-without-dup.md +6 -0
  103. package/corpus/templates/content/changelog/2026-07-18-create-named-workspaces-each-with-its-own-private-files-data.md +6 -0
  104. package/corpus/templates/content/changelog/2026-07-18-favorites-align-with-workspace-and-file-rows-in-the-sidebar.md +6 -0
  105. package/corpus/templates/content/changelog/2026-07-18-local-folder-selection-no-longer-invokes-the-unsafe-native-p.md +6 -0
  106. package/corpus/templates/content/changelog/2026-07-18-made-content-workspaces-independently-expandable-restored-or.md +6 -0
  107. package/corpus/templates/content/changelog/2026-07-18-page-details-now-live-in-a-shared-info-and-comments-rail-dat.md +6 -0
  108. package/corpus/templates/content/changelog/2026-07-18-workspace-database-views-now-control-sidebar-workspace-navig.md +6 -0
  109. package/corpus/templates/content/changelog/2026-07-18-workspace-navigation-now-aligns-favorites-with-workspace-pag.md +6 -0
  110. package/corpus/templates/content/changelog/2026-07-19-favorites-now-open-as-a-table-and-compact-breadcrumbs-make-w.md +6 -0
  111. package/corpus/templates/content/changelog/2026-07-19-files-databases-now-start-unfiltered-sidebar-rows-exactly-fo.md +6 -0
  112. package/corpus/templates/content/changelog/2026-07-19-sidebar-page-trees-now-open-only-when-expanded-remember-thei.md +6 -0
  113. package/corpus/templates/content/changelog/2026-07-19-workspace-file-databases-now-use-the-workspace-name-open-as-.md +6 -0
  114. package/corpus/templates/content/changelog/2026-07-19-workspace-navigation-now-stays-stable-on-hover-uses-folder-i.md +6 -0
  115. package/corpus/templates/content/changelog/2026-07-19-workspace-rows-now-use-folder-icons-and-deleting-a-user-crea.md +6 -0
  116. package/corpus/templates/content/changelog/2026-07-19-workspaces-can-be-created-without-leaving-the-workspaces-dat.md +6 -0
  117. package/corpus/templates/content/e2e/global-setup.ts +3 -2
  118. package/corpus/templates/content/parity/matrix.md +28 -28
  119. package/corpus/templates/content/parity/matrix.ts +8 -2
  120. package/corpus/templates/content/server/db/index.ts +1 -0
  121. package/corpus/templates/content/server/db/schema.ts +10 -0
  122. package/corpus/templates/content/server/lib/documents.ts +12 -7
  123. package/corpus/templates/content/server/plugins/db.ts +17 -0
  124. package/corpus/templates/content/shared/api.ts +9 -0
  125. package/corpus/templates/content/shared/database-form.ts +11 -2
  126. package/corpus/templates/content/vite.config.ts +1 -0
  127. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  128. package/corpus/templates/design/AGENTS.md +5 -0
  129. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  130. package/corpus/templates/dispatch/AGENTS.md +5 -0
  131. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  132. package/corpus/templates/forms/AGENTS.md +5 -0
  133. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  134. package/corpus/templates/macros/AGENTS.md +5 -0
  135. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  136. package/corpus/templates/mail/AGENTS.md +5 -0
  137. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  138. package/corpus/templates/plan/AGENTS.md +5 -0
  139. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  140. package/corpus/templates/slides/AGENTS.md +5 -0
  141. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  142. package/corpus/templates/tasks/AGENTS.md +5 -0
  143. package/dist/cli/create.d.ts.map +1 -1
  144. package/dist/cli/create.js +21 -0
  145. package/dist/cli/create.js.map +1 -1
  146. package/dist/cli/skills.d.ts.map +1 -1
  147. package/dist/cli/skills.js +19 -0
  148. package/dist/cli/skills.js.map +1 -1
  149. package/dist/client/build-compatibility.d.ts +11 -0
  150. package/dist/client/build-compatibility.d.ts.map +1 -0
  151. package/dist/client/build-compatibility.js +56 -0
  152. package/dist/client/build-compatibility.js.map +1 -0
  153. package/dist/client/route-chunk-recovery/index.d.ts +1 -0
  154. package/dist/client/route-chunk-recovery/index.d.ts.map +1 -1
  155. package/dist/client/route-chunk-recovery/index.js +1 -0
  156. package/dist/client/route-chunk-recovery/index.js.map +1 -1
  157. package/dist/client/use-action.d.ts.map +1 -1
  158. package/dist/client/use-action.js +19 -1
  159. package/dist/client/use-action.js.map +1 -1
  160. package/dist/collab/routes.d.ts +1 -1
  161. package/dist/deploy/build.js +2 -1
  162. package/dist/deploy/build.js.map +1 -1
  163. package/dist/notifications/routes.d.ts +1 -1
  164. package/dist/observability/routes.d.ts +3 -3
  165. package/dist/org/context.d.ts +4 -2
  166. package/dist/org/context.d.ts.map +1 -1
  167. package/dist/org/context.js +44 -22
  168. package/dist/org/context.js.map +1 -1
  169. package/dist/progress/routes.d.ts +1 -1
  170. package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
  171. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  172. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  173. package/dist/resources/handlers.d.ts +1 -1
  174. package/dist/server/action-routes.d.ts.map +1 -1
  175. package/dist/server/action-routes.js +32 -2
  176. package/dist/server/action-routes.js.map +1 -1
  177. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  178. package/dist/server/auth-plugin.d.ts.map +1 -1
  179. package/dist/server/auth-plugin.js +9 -5
  180. package/dist/server/auth-plugin.js.map +1 -1
  181. package/dist/server/better-auth-instance.d.ts.map +1 -1
  182. package/dist/server/better-auth-instance.js +4 -1
  183. package/dist/server/better-auth-instance.js.map +1 -1
  184. package/dist/server/transcribe-voice.d.ts +1 -1
  185. package/dist/shared/mcp-embed-headers.d.ts +1 -1
  186. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  187. package/dist/shared/mcp-embed-headers.js +1 -1
  188. package/dist/shared/mcp-embed-headers.js.map +1 -1
  189. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  190. package/dist/templates/chat/AGENTS.md +4 -1
  191. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  192. package/dist/templates/default/AGENTS.md +4 -1
  193. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  194. package/dist/templates/headless/AGENTS.md +5 -1
  195. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
  196. package/dist/templates/workspace-core/AGENTS.md +3 -1
  197. package/dist/templates/workspace-root/AGENTS.md +3 -1
  198. package/dist/vite/client.d.ts +6 -0
  199. package/dist/vite/client.d.ts.map +1 -1
  200. package/dist/vite/client.js +8 -0
  201. package/dist/vite/client.js.map +1 -1
  202. package/package.json +1 -1
  203. package/src/cli/create.ts +23 -0
  204. package/src/cli/skills.ts +24 -0
  205. package/src/client/build-compatibility.ts +77 -0
  206. package/src/client/route-chunk-recovery/index.ts +1 -0
  207. package/src/client/use-action.ts +32 -1
  208. package/src/deploy/build.ts +4 -1
  209. package/src/org/context.ts +56 -30
  210. package/src/server/action-routes.ts +52 -2
  211. package/src/server/auth-plugin.ts +9 -4
  212. package/src/server/better-auth-instance.ts +5 -1
  213. package/src/shared/mcp-embed-headers.ts +1 -1
  214. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  215. package/src/templates/chat/AGENTS.md +4 -1
  216. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  217. package/src/templates/default/AGENTS.md +4 -1
  218. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  219. package/src/templates/headless/AGENTS.md +5 -1
  220. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
  221. package/src/templates/workspace-core/AGENTS.md +3 -1
  222. package/src/templates/workspace-root/AGENTS.md +3 -1
  223. package/src/vite/client.ts +17 -0
package/corpus/README.md CHANGED
@@ -28,6 +28,6 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
 
29
29
  ## Generated Counts
30
30
 
31
- - core files: 1513
31
+ - core files: 1516
32
32
  - toolkit files: 137
33
- - template files: 6055
33
+ - template files: 6101
@@ -1,5 +1,20 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.114.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 3253e1d: Teach generated agents to discover Toolkit capabilities before composing or ejecting shared features.
8
+
9
+ ## 0.114.1
10
+
11
+ ### Patch Changes
12
+
13
+ - c913280: Keep action mutations pending until asynchronous success callbacks finish.
14
+ - c913280: Allow email-password signup without email verification on Netlify deploy previews while preserving explicit verification overrides, and hold auth requests until their serverless routes finish mounting.
15
+ - c913280: Fence incompatible cached browser clients from newer action backends and reload version-aware tabs with a cache-busted build.
16
+ - c913280: Honor an explicit Personal context for users who also belong to organizations.
17
+
3
18
  ## 0.114.0
4
19
 
5
20
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.114.0",
3
+ "version": "0.114.2",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -1697,10 +1697,33 @@ function fixPackageJsonName(
1697
1697
  ) {
1698
1698
  pkg.description = defaultPackageDescriptionForScaffold(name);
1699
1699
  }
1700
+ const scaffoldGuidance = scaffoldGuidanceForTemplate(templateName);
1701
+ if (scaffoldGuidance) {
1702
+ const agentNative =
1703
+ pkg["agent-native"] &&
1704
+ typeof pkg["agent-native"] === "object" &&
1705
+ !Array.isArray(pkg["agent-native"])
1706
+ ? pkg["agent-native"]
1707
+ : {};
1708
+ agentNative.scaffold = {
1709
+ template: trackingTemplateName(templateName),
1710
+ frameworkSkills: scaffoldGuidance,
1711
+ };
1712
+ pkg["agent-native"] = agentNative;
1713
+ }
1700
1714
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
1701
1715
  } catch {}
1702
1716
  }
1703
1717
 
1718
+ function scaffoldGuidanceForTemplate(
1719
+ templateName: string | undefined,
1720
+ ): "default" | "headless" | undefined {
1721
+ if (!templateName || templateName.startsWith("github:")) return undefined;
1722
+ const normalized = normalizeTemplateName(templateName);
1723
+ if (normalized === "headless") return "headless";
1724
+ return getTemplate(normalized) ? "default" : undefined;
1725
+ }
1726
+
1704
1727
  function fixWebManifestName(
1705
1728
  appDir: string,
1706
1729
  name: string,
@@ -1580,6 +1580,27 @@ function hasAgentNativeCoreDependency(
1580
1580
  return false;
1581
1581
  }
1582
1582
 
1583
+ function markedScaffoldGuidanceTemplate(
1584
+ pkg: Record<string, unknown> | undefined,
1585
+ ): "headless" | "default" | undefined {
1586
+ const agentNative = pkg?.["agent-native"];
1587
+ if (
1588
+ !agentNative ||
1589
+ typeof agentNative !== "object" ||
1590
+ Array.isArray(agentNative)
1591
+ ) {
1592
+ return undefined;
1593
+ }
1594
+ const scaffold = (agentNative as Record<string, unknown>).scaffold;
1595
+ if (!scaffold || typeof scaffold !== "object" || Array.isArray(scaffold)) {
1596
+ return undefined;
1597
+ }
1598
+ const frameworkSkills = (scaffold as Record<string, unknown>).frameworkSkills;
1599
+ return frameworkSkills === "headless" || frameworkSkills === "default"
1600
+ ? frameworkSkills
1601
+ : undefined;
1602
+ }
1603
+
1583
1604
  function findWorkspaceCorePackageDir(
1584
1605
  workspaceRoot: string,
1585
1606
  workspaceCoreName: string,
@@ -1634,6 +1655,9 @@ function detectStandaloneScaffoldTemplate(
1634
1655
  return undefined;
1635
1656
  }
1636
1657
 
1658
+ const markedTemplate = markedScaffoldGuidanceTemplate(pkg);
1659
+ if (markedTemplate) return markedTemplate;
1660
+
1637
1661
  const hasAppDir = fs.existsSync(path.join(projectRoot, "app"));
1638
1662
  const hasHeadlessHello = fs.existsSync(
1639
1663
  path.join(projectRoot, "actions", "hello.ts"),
@@ -0,0 +1,77 @@
1
+ declare const __AGENT_NATIVE_BUILD_ID__: string | undefined;
2
+ declare const __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__: string | undefined;
3
+
4
+ const RELOAD_MARKER_KEY = "__agentNativeClientCompatibilityReload";
5
+ export const BUILD_CACHE_BUSTER_PARAM = "__an_build";
6
+
7
+ type CompatibilityWindow = Pick<Window, "location" | "history"> & {
8
+ sessionStorage?: Storage;
9
+ __agentNativeClientCompatibilityReload?: string;
10
+ };
11
+
12
+ export function clientBuildId(): string {
13
+ if (typeof __AGENT_NATIVE_BUILD_ID__ === "string") {
14
+ return __AGENT_NATIVE_BUILD_ID__;
15
+ }
16
+ return (
17
+ (globalThis as typeof globalThis & { __AGENT_NATIVE_BUILD_ID__?: string })
18
+ .__AGENT_NATIVE_BUILD_ID__ ?? ""
19
+ );
20
+ }
21
+
22
+ export function clientCompatibilityVersion(): string {
23
+ if (typeof __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ === "string") {
24
+ return __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__;
25
+ }
26
+ return (
27
+ (
28
+ globalThis as typeof globalThis & {
29
+ __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__?: string;
30
+ }
31
+ ).__AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ ?? ""
32
+ );
33
+ }
34
+
35
+ function readReloadMarker(win: CompatibilityWindow): string {
36
+ try {
37
+ return win.sessionStorage?.getItem(RELOAD_MARKER_KEY) ?? "";
38
+ } catch {
39
+ return win.__agentNativeClientCompatibilityReload ?? "";
40
+ }
41
+ }
42
+
43
+ function writeReloadMarker(win: CompatibilityWindow, marker: string): void {
44
+ win.__agentNativeClientCompatibilityReload = marker;
45
+ try {
46
+ win.sessionStorage?.setItem(RELOAD_MARKER_KEY, marker);
47
+ } catch {}
48
+ }
49
+
50
+ export function reloadForClientCompatibilityMismatch(
51
+ serverBuildId: string,
52
+ requiredCompatibility: string,
53
+ win: CompatibilityWindow | undefined = typeof window === "undefined"
54
+ ? undefined
55
+ : window,
56
+ ): boolean {
57
+ if (!win?.location) return false;
58
+ const marker = `${requiredCompatibility}:${serverBuildId}`;
59
+ if (readReloadMarker(win) === marker) return false;
60
+ writeReloadMarker(win, marker);
61
+ const target = new URL(win.location.href);
62
+ target.searchParams.set(BUILD_CACHE_BUSTER_PARAM, serverBuildId || "latest");
63
+ win.location.replace(target.href);
64
+ return true;
65
+ }
66
+
67
+ export function stripBuildCompatibilityCacheBuster(
68
+ win: CompatibilityWindow | undefined = typeof window === "undefined"
69
+ ? undefined
70
+ : window,
71
+ ): void {
72
+ if (!win?.location || !win.history) return;
73
+ const target = new URL(win.location.href);
74
+ if (!target.searchParams.has(BUILD_CACHE_BUSTER_PARAM)) return;
75
+ target.searchParams.delete(BUILD_CACHE_BUSTER_PARAM);
76
+ win.history.replaceState(win.history.state, "", target.href);
77
+ }
@@ -1 +1,2 @@
1
1
  export * from "../route-chunk-recovery.js";
2
+ export * from "../build-compatibility.js";
@@ -30,6 +30,11 @@ import type {
30
30
  import { trackEvent } from "./analytics.js";
31
31
  import { agentNativePath } from "./api-path.js";
32
32
  import { getBrowserTabId } from "./browser-tab-id.js";
33
+ import {
34
+ clientBuildId,
35
+ clientCompatibilityVersion,
36
+ reloadForClientCompatibilityMismatch,
37
+ } from "./build-compatibility.js";
33
38
  import { ensureEmbedAuthFetchInterceptor } from "./embed-auth.js";
34
39
 
35
40
  const ACTION_PREFIX = agentNativePath("/_agent-native/actions");
@@ -281,6 +286,12 @@ async function performActionFetch<T>(
281
286
  }
282
287
  : {}),
283
288
  };
289
+ const compatibilityVersion = clientCompatibilityVersion();
290
+ if (compatibilityVersion) {
291
+ headers["X-Agent-Native-Client-Compatibility"] = compatibilityVersion;
292
+ }
293
+ const buildId = clientBuildId();
294
+ if (buildId) headers["X-Agent-Native-Build-Id"] = buildId;
284
295
  const tz = resolveUserTimezone();
285
296
  if (tz) headers["x-user-timezone"] = tz;
286
297
  const init: RequestInit = {
@@ -349,6 +360,26 @@ async function performActionFetch<T>(
349
360
  throw new Error(`Action ${name} failed: ${cause}`);
350
361
  }
351
362
 
363
+ if (
364
+ res.status === 409 &&
365
+ res.headers.get("X-Agent-Native-Client-Mismatch") === "1"
366
+ ) {
367
+ const serverBuildId =
368
+ res.headers.get("X-Agent-Native-Build-Id") ?? "latest";
369
+ const requiredCompatibility =
370
+ res.headers.get("X-Agent-Native-Client-Compatibility") ?? "unknown";
371
+ reloadForClientCompatibilityMismatch(
372
+ serverBuildId,
373
+ requiredCompatibility,
374
+ );
375
+ const error = new Error(
376
+ `Action ${name} requires a refreshed browser client`,
377
+ );
378
+ (error as any).status = 409;
379
+ (error as any).code = "client_build_mismatch";
380
+ throw error;
381
+ }
382
+
352
383
  // 204 No Content — nothing to parse.
353
384
  if (res.status === 204) return null as T;
354
385
 
@@ -760,7 +791,7 @@ export function useActionMutation<
760
791
  if (!skipActionQueryInvalidation) {
761
792
  queryClient.invalidateQueries({ queryKey: ["action"] });
762
793
  }
763
- (onSuccess as Function)?.(...args);
794
+ return (onSuccess as Function)?.(...args);
764
795
  },
765
796
  });
766
797
  }
@@ -1240,7 +1240,7 @@ async function getHandler() {
1240
1240
  headers: {
1241
1241
  "Access-Control-Allow-Origin": "*",
1242
1242
  "Access-Control-Allow-Methods": "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS",
1243
- "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Embed-Target",
1243
+ "Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-Agent-Native-Embed-Target",
1244
1244
  },
1245
1245
  });
1246
1246
  }
@@ -3479,6 +3479,9 @@ export default bundle;
3479
3479
  "process.env.AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID": JSON.stringify(
3480
3480
  process.env.GA_MEASUREMENT_ID?.trim() || "",
3481
3481
  ),
3482
+ "process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(
3483
+ process.env.CONTEXT?.trim() || "",
3484
+ ),
3482
3485
  },
3483
3486
  // Replace browser-only renderers (Excalidraw/Mermaid) with an inert proxy in
3484
3487
  // the server bundle. Without this, Nitro's Rolldown build pulls the real
@@ -41,7 +41,8 @@ const nanoid = (): string =>
41
41
  /**
42
42
  * Resolve the current user's organization context from their session.
43
43
  *
44
- * - For users in multiple orgs, honors their `active-org-id` user setting.
44
+ * - Honors the user's `active-org-id` setting, including an explicit Personal
45
+ * context represented by `{ orgId: null }`.
45
46
  * - Falls back to the user's first membership.
46
47
  * - When the authenticated user has zero memberships, provisions a default org
47
48
  * named after the user ({name}'s workspace, falling back to the email
@@ -63,6 +64,34 @@ export async function getOrgContext(event: H3Event): Promise<OrgContext> {
63
64
  type MembershipRow = { orgId: string; role: OrgRole; orgName: string };
64
65
 
65
66
  const MEMBERSHIPS_CACHE_KEY = "__anOrgMembershipsCache";
67
+ const ACTIVE_ORG_SETTING_CACHE_KEY = "__anActiveOrgSettingCache";
68
+
69
+ type ActiveOrgSetting = { orgId: string | null } | null;
70
+
71
+ function loadActiveOrgSettingForEvent(
72
+ event: H3Event,
73
+ email: string,
74
+ ): Promise<ActiveOrgSetting> {
75
+ const ctx = event.context as Record<string, unknown>;
76
+ const cache = ((ctx[ACTIVE_ORG_SETTING_CACHE_KEY] as
77
+ | Map<string, Promise<ActiveOrgSetting>>
78
+ | undefined) ??
79
+ (ctx[ACTIVE_ORG_SETTING_CACHE_KEY] = new Map<
80
+ string,
81
+ Promise<ActiveOrgSetting>
82
+ >())) as Map<string, Promise<ActiveOrgSetting>>;
83
+ const normalizedEmail = email.toLowerCase();
84
+ let promise = cache.get(normalizedEmail);
85
+ if (!promise) {
86
+ promise = getUserSetting(email, "active-org-id").then((value) => {
87
+ if (!value || !("orgId" in value)) return null;
88
+ if (value.orgId === null) return { orgId: null };
89
+ return typeof value.orgId === "string" ? { orgId: value.orgId } : null;
90
+ });
91
+ cache.set(normalizedEmail, promise);
92
+ }
93
+ return promise;
94
+ }
66
95
 
67
96
  /**
68
97
  * Per-request memoization of the org_members lookup, keyed by email on
@@ -128,32 +157,29 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
128
157
  return { email, orgId: null, orgName: null, role: null };
129
158
  }
130
159
 
131
- if (memberships.length > 1) {
132
- const activeOrgSetting = (await getUserSetting(email, "active-org-id")) as {
133
- orgId: string;
134
- } | null;
135
- if (activeOrgSetting?.orgId) {
136
- const active = memberships.find(
137
- (m) => m.orgId === activeOrgSetting.orgId,
138
- );
139
- if (active) {
140
- return {
141
- email,
142
- orgId: active.orgId,
143
- orgName: active.orgName,
144
- role: active.role,
145
- };
146
- }
160
+ const shouldTryDomainAutoJoin =
161
+ memberships.length === 0 ||
162
+ (memberships.length === 1 &&
163
+ isLikelyPersonalWorkspace(memberships[0], email, session));
164
+ const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
165
+ if (activeOrgSetting?.orgId === null) {
166
+ return { email, orgId: null, orgName: null, role: null };
167
+ }
168
+ if (activeOrgSetting?.orgId) {
169
+ const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
170
+ if (active && !shouldTryDomainAutoJoin) {
171
+ return {
172
+ email,
173
+ orgId: active.orgId,
174
+ orgName: active.orgName,
175
+ role: active.role,
176
+ };
147
177
  }
148
178
  }
149
179
 
150
180
  const sessionMembership = sessionOrgId
151
181
  ? memberships.find((m) => m.orgId === sessionOrgId)
152
182
  : null;
153
- const shouldTryDomainAutoJoin =
154
- memberships.length === 0 ||
155
- (memberships.length === 1 &&
156
- isLikelyPersonalWorkspace(memberships[0], email, session));
157
183
 
158
184
  if (shouldTryDomainAutoJoin) {
159
185
  const joined = await autoJoinDomainMatchingOrgs(email, {
@@ -248,7 +274,8 @@ async function loadMemberships(
248
274
  /**
249
275
  * Resolve the active org ID for a given email — for non-HTTP contexts like
250
276
  * the integration webhook handler where we have an email but no event/session.
251
- * Picks the user's active-org-id setting if set, otherwise the first membership.
277
+ * Picks the user's active-org-id setting if set, including explicit Personal,
278
+ * otherwise the first membership.
252
279
  * Returns null if the user has no memberships.
253
280
  */
254
281
  export async function resolveOrgIdForEmail(
@@ -263,10 +290,11 @@ export async function resolveOrgIdForEmail(
263
290
  });
264
291
  if (rows.length === 0) return null;
265
292
  const ids = rows.map((r: any) => String(r.org_id));
266
- if (ids.length === 1) return ids[0];
267
- const activeOrgSetting = (await getUserSetting(email, "active-org-id")) as {
268
- orgId: string;
269
- } | null;
293
+ const activeOrgSetting = (await getUserSetting(
294
+ email,
295
+ "active-org-id",
296
+ )) as ActiveOrgSetting;
297
+ if (activeOrgSetting?.orgId === null) return null;
270
298
  if (activeOrgSetting?.orgId && ids.includes(activeOrgSetting.orgId)) {
271
299
  return activeOrgSetting.orgId;
272
300
  }
@@ -291,10 +319,8 @@ export async function resolveOrgIdForEmailViaEvent(
291
319
  if (!exec) return null;
292
320
  const memberships = await loadMembershipsForEvent(event, exec, email);
293
321
  if (!memberships || memberships.length === 0) return null;
294
- if (memberships.length === 1) return memberships[0].orgId;
295
- const activeOrgSetting = (await getUserSetting(email, "active-org-id")) as {
296
- orgId: string;
297
- } | null;
322
+ const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
323
+ if (activeOrgSetting?.orgId === null) return null;
298
324
  if (
299
325
  activeOrgSetting?.orgId &&
300
326
  memberships.some((m) => m.orgId === activeOrgSetting.orgId)
@@ -30,6 +30,26 @@ import {
30
30
  getAllowedCorsOrigin as resolveAllowedCorsOrigin,
31
31
  readCorsAllowedOrigins,
32
32
  } from "./cors-origins.js";
33
+
34
+ declare const __AGENT_NATIVE_BUILD_ID__: string | undefined;
35
+ declare const __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__: string | undefined;
36
+
37
+ function requiredClientCompatibilityVersion(): string {
38
+ const configured =
39
+ typeof __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ === "string"
40
+ ? __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__
41
+ : process.env.AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION;
42
+ return configured?.trim() ?? "";
43
+ }
44
+
45
+ function currentBuildId(): string {
46
+ const configured =
47
+ typeof __AGENT_NATIVE_BUILD_ID__ === "string"
48
+ ? __AGENT_NATIVE_BUILD_ID__
49
+ : process.env.AGENT_NATIVE_BUILD_ID;
50
+ return configured?.trim() || "unknown";
51
+ }
52
+
33
53
  /**
34
54
  * Auto-mount actions as HTTP endpoints under /_agent-native/actions/:name.
35
55
  *
@@ -187,8 +207,8 @@ function handleOptionsRequest(event: any): string {
187
207
  event,
188
208
  "Access-Control-Allow-Headers",
189
209
  cors.credentials
190
- ? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,${EMBED_TARGET_HEADER}`
191
- : `${MCP_EMBED_CORS_ALLOW_HEADERS},X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend`,
210
+ ? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,${EMBED_TARGET_HEADER}`
211
+ : `${MCP_EMBED_CORS_ALLOW_HEADERS},X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id`,
192
212
  );
193
213
  }
194
214
 
@@ -320,6 +340,11 @@ export function mountActionRoutes(
320
340
  }
321
341
 
322
342
  setResponseHeader(event, "Cache-Control", "no-store");
343
+ setResponseHeader(
344
+ event,
345
+ "Access-Control-Expose-Headers",
346
+ "X-Agent-Native-Client-Mismatch,X-Agent-Native-Build-Id,X-Agent-Native-Client-Compatibility",
347
+ );
323
348
 
324
349
  // Allow the declared method
325
350
  if (effectiveMethod !== method) {
@@ -327,6 +352,31 @@ export function mountActionRoutes(
327
352
  return { error: `Method not allowed. Use ${method}.` };
328
353
  }
329
354
 
355
+ const requiredCompatibility = requiredClientCompatibilityVersion();
356
+ if (isFrontendActionRequest(event) && requiredCompatibility) {
357
+ const receivedCompatibility = getHeader(
358
+ event,
359
+ "x-agent-native-client-compatibility",
360
+ );
361
+ if (receivedCompatibility !== requiredCompatibility) {
362
+ const serverBuildId = currentBuildId();
363
+ setResponseStatus(event, 409);
364
+ setResponseHeader(event, "X-Agent-Native-Client-Mismatch", "1");
365
+ setResponseHeader(event, "X-Agent-Native-Build-Id", serverBuildId);
366
+ setResponseHeader(
367
+ event,
368
+ "X-Agent-Native-Client-Compatibility",
369
+ requiredCompatibility,
370
+ );
371
+ return {
372
+ error: "This browser tab must reload before it can use this app.",
373
+ code: "client_build_mismatch",
374
+ serverBuildId,
375
+ requiredCompatibility,
376
+ };
377
+ }
378
+ }
379
+
330
380
  // (audit H5) Per-action `toolCallable` opt-out for the tools-iframe
331
381
  // bridge. The bridge tags every outbound action call with
332
382
  // X-Agent-Native-Tool-Bridge: 1. When that header is present and the
@@ -4,16 +4,21 @@ import {
4
4
  getH3App,
5
5
  awaitBootstrap,
6
6
  markDefaultPluginProvided,
7
+ trackPluginInit,
7
8
  } from "./framework-request-handler.js";
8
9
 
9
10
  type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
10
11
 
11
12
  export function createAuthPlugin(options?: AuthOptions): NitroPluginDef {
12
- return async (nitroApp: any) => {
13
+ return (nitroApp: any) => {
13
14
  markDefaultPluginProvided(nitroApp, "auth");
14
- // Wait for any other default plugins to finish mounting first.
15
- await awaitBootstrap(nitroApp);
16
- await autoMountAuth(getH3App(nitroApp), options);
15
+ const initPromise = (async () => {
16
+ await awaitBootstrap(nitroApp);
17
+ await autoMountAuth(getH3App(nitroApp), options);
18
+ })();
19
+ trackPluginInit(nitroApp, initPromise, {
20
+ paths: ["/_agent-native/auth"],
21
+ });
17
22
  };
18
23
  }
19
24
 
@@ -317,8 +317,12 @@ export function resolveSignupTrackingProperties(): Record<string, string> {
317
317
  export function shouldSkipEmailVerification(): boolean {
318
318
  const value = process.env.AUTH_SKIP_EMAIL_VERIFICATION;
319
319
  if (value == null) {
320
+ const deployContext =
321
+ process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT || process.env.CONTEXT;
320
322
  return (
321
- process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test"
323
+ process.env.NODE_ENV === "development" ||
324
+ process.env.NODE_ENV === "test" ||
325
+ deployContext === "deploy-preview"
322
326
  );
323
327
  }
324
328
  const normalized = value.trim().toLowerCase();
@@ -1,5 +1,5 @@
1
1
  export const MCP_EMBED_CORS_ALLOW_HEADERS =
2
- "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Frontend,X-User-Timezone,X-Agent-Native-Embed-Target,X-Agent-Native-Embed-Transplant";
2
+ "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-User-Timezone,X-Agent-Native-Embed-Target,X-Agent-Native-Embed-Transplant";
3
3
  export const EMBED_TRANSPLANT_HEADER = "x-agent-native-embed-transplant";
4
4
 
5
5
  const CLAUDE_MCP_CONTENT_HOST_RE = /^[a-f0-9]{32}\.claudemcpcontent\.com$/i;
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: agent-native-toolkit
3
+ description: >-
4
+ Inventory and ownership rules for shared Agent Native workspace UI. Use
5
+ before building app chrome, settings, navigation, sharing, collaboration,
6
+ setup, history, comments, chat rails, agent UX, or repeated workspace behavior.
7
+ scope: dev
8
+ metadata:
9
+ internal: true
10
+ ---
11
+
12
+ # Agent-Native Toolkit
13
+
14
+ Use this skill when deciding whether app chrome, settings, collaboration,
15
+ sharing, navigation, organization, setup, history, comments, or agent UX should
16
+ be built app-locally or moved into reusable framework/toolkit pieces.
17
+
18
+ ## Core Rule
19
+
20
+ Apps own domain models, domain actions, and product-specific workflows. The
21
+ framework and `@agent-native/toolkit` own repeated workspace behavior users
22
+ expect to work the same everywhere.
23
+
24
+ Move behavior into shared toolkit primitives when it is:
25
+
26
+ - workspace-wide, such as settings, nav, search, org membership, or setup
27
+ - agent-visible, such as context, actions, run progress, or proof-of-done
28
+ - governed, such as secrets, permissions, sharing, audit, or billing
29
+ - repeated by two or more apps
30
+ - not tied to one domain model
31
+
32
+ Keep behavior app-local when the abstraction would hide important domain
33
+ language or make a simple app-specific workflow harder to understand.
34
+
35
+ ## Discover Before Building
36
+
37
+ Before creating an app-local version of repeated workspace or agent UI:
38
+
39
+ 1. Check the reusable kits below and the installed package documentation.
40
+ 2. Search installed public components and source with `docs-search` and
41
+ `source-search`.
42
+ 3. Run `agent-native eject --list` to see the version-matched units published
43
+ by the packages installed in this app.
44
+ 4. Read `customizing-agent-native` and configure, compose, or eject the
45
+ smallest unit instead of recreating shared behavior from memory.
46
+
47
+ Use public package exports at runtime. Published source and ejection manifests
48
+ are discovery and ownership-transfer mechanisms, not private runtime APIs.
49
+
50
+ ## Settings Direction
51
+
52
+ Durable settings belong in the Settings app or a registered settings route. The
53
+ agent sidebar should not become a second settings app. It can show contextual
54
+ quick controls and deep links such as:
55
+
56
+ - `/settings/ai`
57
+ - `/settings/connections`
58
+ - `/settings/secrets`
59
+ - `/settings/usage`
60
+ - `/settings/apps/:appId`
61
+
62
+ When adding a new API key, OAuth grant, provider connection, model selector, app
63
+ preference, notification preference, or usage/billing surface, register it as a
64
+ settings tab or app settings panel first. Only add sidebar UI when it is needed
65
+ in the moment of agent use.
66
+
67
+ ## Reusable Kits
68
+
69
+ - **Settings kit**: a searchable settings page with account, workspace, AI
70
+ models, LLM keys, connections, secrets, usage, notifications, changelog, and
71
+ app-specific panels. Search is on by default; register a `SettingsSearchEntry`
72
+ per control so users find settings by name across tabs.
73
+ - **Collaboration kit**: Yjs docs, presence, agent presence, live cursors,
74
+ remote selections, recent edit highlights, real-time sync indicators, and
75
+ undo/redo grouping.
76
+ - **Sharing kit**: private/workspace/org/public-link access, invites, roles,
77
+ expirations, agent-readable links, and resource registration.
78
+ - **Navigation and command kit**: app shell, side nav, breadcrumbs, app switcher,
79
+ command palette entries, recent resources, pinned resources, and global search.
80
+ - **Organization kit**: folders, tags, favorites, archive, trash, ownership,
81
+ membership, and common resource metadata.
82
+ - **Setup and connections kit**: declarative setup requirements, model readiness,
83
+ missing-secret states, OAuth grants, and provider connection health.
84
+ - **Agent UX kit**: sidebar, composer, staged context, mentions, voice, human
85
+ approval, generative UI, progress, and screen-state exposure.
86
+ - **Chat history kit**: presentational chat lists and recent-chat rails belong
87
+ in Toolkit; Core keeps thread persistence, agent execution, transport, and
88
+ page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
89
+ - **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
90
+ `@agent-native/core/client`) with Context, Files, Connections, Jobs, and
91
+ Access tabs plus a Personal/Organization scope toggle. The canonical home
92
+ for context transparency, MCP servers, A2A remote agents, recurring
93
+ jobs/automations, and external-client connect flows. See the `agent-page`
94
+ skill.
95
+ - **History and recovery kit**: audit log, activity feed, version history,
96
+ checkpoints, undo, redo, restore, and proof-of-done.
97
+ - **Comments and review kit**: anchored comments, pins, mentions, review
98
+ requests, resolved threads, agent follow-up tasks, and notifications.
99
+ - **Workflow and observability kit**: notifications, approvals, scheduled work,
100
+ background runs, recurring jobs, traces, evals, feedback, and run timelines.
101
+
102
+ ## Implementation Checklist
103
+
104
+ When adding or refactoring one of these areas:
105
+
106
+ 1. Search existing framework and template code for duplicated UI or actions.
107
+ 2. Decide the shared contract: data shape, action API, React component/hook, and
108
+ app adapter points.
109
+ 3. Keep shared data provider-agnostic and scoped by auth/sharing rules.
110
+ 4. Expose the same capability to the UI and agent through actions or documented
111
+ client helpers.
112
+ 5. Register app-specific labels, routes, resource adapters, and settings panels
113
+ instead of hardcoding app names in core UI.
114
+ 6. Update docs and relevant skills so future apps discover the shared path.
115
+ 7. Keep the component easy to adopt piecemeal: expose props/slots first and
116
+ ship readable source plus a complete ejection unit so apps can take ownership
117
+ of the smallest feature when needed. See `customizing-agent-native` for the
118
+ configure → compose → eject → propose seam ladder.
119
+
120
+ ## Related Skills
121
+
122
+ Read these alongside this skill when the work touches the specific area:
123
+
124
+ - `sharing`
125
+ - `real-time-collab`
126
+ - `real-time-sync`
127
+ - `client-side-routing`
128
+ - `context-awareness`
129
+ - `onboarding`
130
+ - `secrets`
131
+ - `audit-log`
132
+ - `observability`
133
+ - `frontend-design`