@agent-native/core 0.214.0 → 0.217.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 (196) hide show
  1. package/dist/action.js +54 -1
  2. package/dist/agent/actions/disconnect-chatgpt-subscription.js +5 -0
  3. package/dist/agent/actions/get-agentkit-capabilities.js +3 -3
  4. package/dist/agent/actions/manage-builder-connection.js +5 -0
  5. package/dist/agent/actions/manage-provider-key-policy.js +5 -0
  6. package/dist/agent/actions/manage-provider-models.js +5 -0
  7. package/dist/agent/actions/manage-service-providers.js +5 -0
  8. package/dist/agent/actions/select-chatgpt-subscription-account.js +5 -0
  9. package/dist/agent/context-xray/actions/context-evict.js +5 -0
  10. package/dist/agent/context-xray/actions/context-pin.js +5 -0
  11. package/dist/agent/context-xray/actions/context-report.js +5 -0
  12. package/dist/agent/context-xray/actions/context-restore.js +5 -0
  13. package/dist/agent/execution-fence.d.ts +1 -0
  14. package/dist/agent/execution-fence.js +5 -0
  15. package/dist/agent/production-agent.d.ts +35 -2
  16. package/dist/agent/production-agent.js +629 -32
  17. package/dist/agent/run-manager.d.ts +2 -0
  18. package/dist/agent/run-manager.js +397 -115
  19. package/dist/agent/run-slot-lock.d.ts +2 -0
  20. package/dist/agent/run-slot-lock.js +6 -0
  21. package/dist/agent/run-store.d.ts +5 -0
  22. package/dist/agent/run-store.js +423 -156
  23. package/dist/agent/thread-data-builder.js +27 -5
  24. package/dist/agent/types.d.ts +6 -12
  25. package/dist/agentkit/capabilities.d.ts +1 -1
  26. package/dist/app-config/analytics.js +1 -1
  27. package/dist/application-state/store.d.ts +5 -0
  28. package/dist/application-state/store.js +26 -0
  29. package/dist/automation/index.d.ts +1 -1
  30. package/dist/chat-threads/schema-migrations.js +17 -0
  31. package/dist/chat-threads/store.d.ts +21 -1
  32. package/dist/chat-threads/store.js +223 -41
  33. package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
  34. package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
  35. package/dist/cli/templates-meta.js +14 -0
  36. package/dist/client/analytics-session.d.ts +7 -0
  37. package/dist/client/analytics-session.js +27 -1
  38. package/dist/client/analytics.js +276 -31
  39. package/dist/client/chat/agentkit-agent-native.js +79 -3
  40. package/dist/client/chat/agentkit-protocol.js +80 -42
  41. package/dist/client/chat/runtime.d.ts +5 -1
  42. package/dist/client/chat/runtime.js +46 -3
  43. package/dist/client/consent.d.ts +48 -0
  44. package/dist/client/consent.js +413 -0
  45. package/dist/client/onboarding/index.d.ts +1 -0
  46. package/dist/client/onboarding/index.js +1 -0
  47. package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
  48. package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
  49. package/dist/client/review/use-review.d.ts +2 -0
  50. package/dist/client/review/use-review.js +28 -1
  51. package/dist/client/session-replay.d.ts +1 -1
  52. package/dist/client/session-replay.js +142 -3
  53. package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
  54. package/dist/client/sharing/useResourceAccessGate.js +9 -1
  55. package/dist/client/use-chat-thread-list.d.ts +2 -0
  56. package/dist/client/use-chat-thread-list.js +12 -2
  57. package/dist/client/use-chat-threads.d.ts +1 -0
  58. package/dist/client/use-chat-threads.js +2 -0
  59. package/dist/collab/awareness.d.ts +2 -2
  60. package/dist/connections/catalog.d.ts +5 -5
  61. package/dist/connections/catalog.js +22 -3
  62. package/dist/data-widgets/index.d.ts +36 -2
  63. package/dist/data-widgets/index.js +94 -6
  64. package/dist/db/migrations.js +4 -1
  65. package/dist/db/schema-snapshot.generated.js +8 -1
  66. package/dist/feature-flags/actions/set-feature-flag.js +5 -0
  67. package/dist/feature-flags/index.d.ts +1 -1
  68. package/dist/feature-flags/index.js +1 -1
  69. package/dist/feature-flags/store.d.ts +12 -0
  70. package/dist/feature-flags/store.js +79 -7
  71. package/dist/file-upload/actions/manage-file-storage.js +5 -0
  72. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  73. package/dist/file-upload/actions/upload-image.js +5 -0
  74. package/dist/history/actions/create-resource-version.js +5 -0
  75. package/dist/history/actions/restore-resource-version.js +5 -0
  76. package/dist/ingestion/index.d.ts +1 -1
  77. package/dist/ingestion/index.js +1 -1
  78. package/dist/ingestion/pptx.d.ts +11 -0
  79. package/dist/ingestion/pptx.js +81 -1
  80. package/dist/integrations/actions/manage-messaging-channel.js +5 -0
  81. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  82. package/dist/jobs/scheduler.js +17 -1
  83. package/dist/labs/actions/set-lab.js +5 -0
  84. package/dist/localization/actions/set-localization-preference.js +5 -0
  85. package/dist/localization/consent-banner-messages.d.ts +16 -0
  86. package/dist/localization/consent-banner-messages.js +149 -0
  87. package/dist/localization/core-messages.js +4 -0
  88. package/dist/localization/default-messages.d.ts +1 -0
  89. package/dist/localization/default-messages.js +2 -0
  90. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  91. package/dist/notifications/routes.d.ts +2 -2
  92. package/dist/observability/actions/save-observability-instruction-update.js +5 -0
  93. package/dist/observability/actions/save-observability-review-summary.js +5 -0
  94. package/dist/observability/routes.d.ts +6 -6
  95. package/dist/onboarding/index.d.ts +2 -1
  96. package/dist/onboarding/index.js +1 -0
  97. package/dist/onboarding/plugin.js +55 -46
  98. package/dist/onboarding/status.d.ts +15 -0
  99. package/dist/onboarding/status.js +59 -0
  100. package/dist/onboarding/types.d.ts +12 -0
  101. package/dist/onboarding/types.js +2 -1
  102. package/dist/org/workspace-app-access.js +19 -9
  103. package/dist/progress/routes.d.ts +1 -1
  104. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  105. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  106. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  107. package/dist/provider-api/index.js +9 -2
  108. package/dist/resources/handlers.d.ts +1 -1
  109. package/dist/review/actions/consume-review-feedback.js +5 -0
  110. package/dist/review/actions/create-review-comment.js +5 -0
  111. package/dist/review/actions/delete-review-comment.js +5 -0
  112. package/dist/review/actions/react-to-review-comment.js +5 -0
  113. package/dist/review/actions/reply-review-comment.js +5 -0
  114. package/dist/review/actions/resolve-review-thread.js +5 -0
  115. package/dist/review/actions/send-review-thread-to-agent.js +5 -0
  116. package/dist/review/actions/set-review-status.js +5 -0
  117. package/dist/review/actions/set-review-thread-muted.js +5 -0
  118. package/dist/review/actions/set-review-thread-unread.js +5 -0
  119. package/dist/review/actions/set-review-threads-unread.js +5 -0
  120. package/dist/review/actions/update-review-comment-anchor.js +5 -0
  121. package/dist/review/actions/update-review-comment.js +5 -0
  122. package/dist/review/suggestions/actions.js +60 -21
  123. package/dist/review/suggestions/store.d.ts +2 -0
  124. package/dist/review/suggestions/store.js +28 -0
  125. package/dist/secrets/actions/delete-api-key.js +5 -0
  126. package/dist/secrets/routes.d.ts +6 -6
  127. package/dist/server/agent-capabilities.js +13 -6
  128. package/dist/server/agent-chat/context-tools.js +63 -2
  129. package/dist/server/agent-chat-plugin.d.ts +2 -0
  130. package/dist/server/agent-chat-plugin.js +242 -54
  131. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  132. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  133. package/dist/server/analytics.d.ts +0 -1
  134. package/dist/server/analytics.js +81 -20
  135. package/dist/server/application-state-maintenance.d.ts +2 -0
  136. package/dist/server/application-state-maintenance.js +2 -0
  137. package/dist/server/attribution.d.ts +14 -0
  138. package/dist/server/attribution.js +62 -2
  139. package/dist/server/auth.js +7 -0
  140. package/dist/server/builder-api-auth.d.ts +7 -0
  141. package/dist/server/builder-api-auth.js +24 -0
  142. package/dist/server/builder-oauth.d.ts +5 -1
  143. package/dist/server/builder-oauth.js +5 -0
  144. package/dist/server/consent-route.d.ts +41 -0
  145. package/dist/server/consent-route.js +102 -0
  146. package/dist/server/core-routes-plugin.d.ts +1 -1
  147. package/dist/server/first-touch-route.d.ts +39 -0
  148. package/dist/server/first-touch-route.js +115 -0
  149. package/dist/server/index.d.ts +2 -1
  150. package/dist/server/index.js +2 -1
  151. package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
  152. package/dist/server/queued-submission-inbox-drain.js +12 -0
  153. package/dist/server/request-origin.d.ts +6 -0
  154. package/dist/server/request-origin.js +12 -0
  155. package/dist/settings/org-settings.d.ts +2 -1
  156. package/dist/settings/org-settings.js +4 -1
  157. package/dist/settings/store.d.ts +8 -0
  158. package/dist/settings/store.js +14 -5
  159. package/dist/shared/consent.d.ts +33 -0
  160. package/dist/shared/consent.js +149 -0
  161. package/dist/shared/first-touch-persistence.d.ts +31 -0
  162. package/dist/shared/first-touch-persistence.js +53 -0
  163. package/dist/sharing/actions/set-resource-visibility.js +5 -0
  164. package/dist/sharing/actions/share-resource.js +5 -0
  165. package/dist/sharing/actions/unshare-resource.js +5 -0
  166. package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  167. package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  168. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  169. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  170. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  171. package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  172. package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  173. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
  174. package/dist/triggers/actions/manage-automation.d.ts +4 -4
  175. package/dist/usage/actions/get-usage-metrics.js +27 -4
  176. package/dist/usage/actions/manage-usage-alert.js +5 -0
  177. package/dist/vite/client.js +8 -6
  178. package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
  179. package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
  180. package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
  181. package/docs/content/actions-access-control.mdx +8 -8
  182. package/docs/content/actions-defining.mdx +9 -8
  183. package/docs/content/deployment-environment-variables.mdx +1 -1
  184. package/docs/content/environment-variables.mdx +1 -1
  185. package/docs/content/template-design-developers.mdx +9 -9
  186. package/docs/content/template-design-features.mdx +1 -3
  187. package/docs/content/turn-into-app.mdx +4 -0
  188. package/package.json +6 -3
  189. package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  190. package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  191. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  192. package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  193. package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  194. package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  195. package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  196. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
- import { defineAction } from "../../action.js";
3
- import { ALL_USAGE_APPS, listAppUsageMetrics, USAGE_APP_FILTER_ALL, USAGE_APP_FILTER_CURRENT, } from "../metrics-store.js";
2
+ import { defineAction, fail } from "../../action.js";
3
+ import { isOrgMember } from "../../org/membership.js";
4
+ import { ALL_USAGE_APPS, canViewWorkspaceUsage, listAppUsageMetrics, USAGE_APP_FILTER_ALL, USAGE_APP_FILTER_CURRENT, } from "../metrics-store.js";
4
5
  import { resolveUsageAppKey } from "../store.js";
5
6
  function resolveAppSelection(app, appId) {
6
7
  if (appId !== undefined) {
@@ -16,12 +17,17 @@ function resolveAppSelection(app, appId) {
16
17
  return app;
17
18
  }
18
19
  export default defineAction({
19
- description: 'Get LLM usage metrics for Settings › Usage: lookback totals, the daily trend split by feature, app, model and surface (dailyBy), top features, models, apps, chats and people, tool calls per day, recent prompts, and the apps with usage. Covers every app unless app names one. Members see only their own usage; scope "workspace" (everyone in the organization) is for owners and admins. billing.unit identifies Builder.io credits, estimated dollars, mixed billing, or unknown when historical engine metadata is missing.',
20
+ description: "Reports this workspace's own agent/LLM usage (Settings › Usage) for members of this organization only; it does NOT cover usage, credits, or activity of external customers, accounts, companies, or product usage, use this app's own customer or billing actions for those, or the app that owns that data (see <relevant-apps>, or search with describe-workspace-apps). Returns lookback totals, the daily trend (dailyBy feature, app, model and surface), top features, models, apps, chats and people, tool calls per day, and recent prompts, across every app unless app names one. Members see only their own usage; scope \"workspace\" (everyone in the organization) is for owners and admins. billing.unit identifies Builder.io credits, estimated dollars, mixed billing, or unknown.",
20
21
  http: { method: "GET" },
21
22
  schema: z.object({
22
23
  sinceDays: z.coerce.number().int().min(1).max(365).default(30),
23
24
  scope: z.enum(["me", "workspace"]).default("me"),
24
- userEmail: z.string().trim().min(1).optional(),
25
+ userEmail: z
26
+ .string()
27
+ .trim()
28
+ .min(1)
29
+ .optional()
30
+ .describe("Email of a member of this organization to filter usage to. Not for customers or other external accounts."),
25
31
  app: z
26
32
  .string()
27
33
  .trim()
@@ -39,6 +45,23 @@ export default defineAction({
39
45
  run: async ({ sinceDays, scope, userEmail, app, appId }, ctx) => {
40
46
  if (!ctx?.userEmail)
41
47
  throw new Error("Not authenticated.");
48
+ // scope "me" ignores userEmail, so only a workspace lookup is checked.
49
+ if (scope === "workspace" &&
50
+ userEmail &&
51
+ ctx.orgId &&
52
+ userEmail.toLowerCase() !== ctx.userEmail.toLowerCase()) {
53
+ // Unauthorized callers get one answer whether or not the email is a
54
+ // member, so the lookup cannot be used to probe the roster.
55
+ if (!(await canViewWorkspaceUsage({
56
+ ownerEmail: ctx.userEmail,
57
+ orgId: ctx.orgId,
58
+ }))) {
59
+ fail(`get-usage-metrics cannot answer this. For a teammate in this organization, only owners and admins can look up their usage. For a customer or other external user, get-usage-metrics has no data: use this app's own customer or billing actions if it has any, or find the app that owns that data with describe-workspace-apps query="<what you need>" and delegate with call-agent.`, { errorCode: "usage_user_lookup_forbidden", statusCode: 403 });
60
+ }
61
+ if (!(await isOrgMember(ctx.orgId, userEmail))) {
62
+ fail(`${userEmail} is not a member of this organization, so get-usage-metrics has no data on them. For a customer's or account's usage or credits, use this app's own customer or billing actions if it has any, or find the app that owns that data with describe-workspace-apps query="<what you need>" and delegate with call-agent.`, { errorCode: "usage_user_not_org_member", statusCode: 404 });
63
+ }
64
+ }
42
65
  const selection = resolveAppSelection(app, appId);
43
66
  return listAppUsageMetrics({ sinceDays, scope, userEmail, builderCreditsEnabled: true }, {
44
67
  ownerEmail: ctx.userEmail,
@@ -15,6 +15,11 @@ export default defineAction({
15
15
  channels: z.array(channel).min(1).optional(),
16
16
  enabled: z.boolean().optional(),
17
17
  }),
18
+ mcpAnnotations: {
19
+ readOnlyHint: false,
20
+ destructiveHint: false,
21
+ openWorldHint: false,
22
+ },
18
23
  run: async ({ operation, scope, ruleId, appId, unit, period, limit, channels, enabled }, ctx) => {
19
24
  if (!ctx?.userEmail)
20
25
  throw new Error("Not authenticated.");
@@ -982,7 +982,6 @@ function getDefaultOptimizeDeps(cwd) {
982
982
  specifier: "@modelcontextprotocol/ext-apps/app-bridge",
983
983
  packageName: "@modelcontextprotocol/ext-apps",
984
984
  },
985
- { specifier: "@paper-design/shaders-react" },
986
985
  { specifier: "@radix-ui/react-accordion" },
987
986
  { specifier: "@radix-ui/react-alert-dialog" },
988
987
  { specifier: "@radix-ui/react-aspect-ratio" },
@@ -3482,11 +3481,14 @@ const DEFAULT_VITE_WATCH_IGNORED_DIRS = new Set([
3482
3481
  "build",
3483
3482
  ]);
3484
3483
  export function defaultViteWatchIgnored(root) {
3485
- return (file) => path
3486
- .relative(root, file)
3487
- .split(/[\\/]/)
3488
- .slice(0, -1)
3489
- .some((segment) => DEFAULT_VITE_WATCH_IGNORED_DIRS.has(segment));
3484
+ return (file) => {
3485
+ const segments = path.relative(root, file).split(/[\\/]/);
3486
+ return segments
3487
+ .slice(0, -1)
3488
+ .some((segment, index) => segment === ".generated" && index === 0 && segments[1] === "bridge"
3489
+ ? false
3490
+ : DEFAULT_VITE_WATCH_IGNORED_DIRS.has(segment));
3491
+ };
3490
3492
  }
3491
3493
  function forceServeOnly(pluginOrPreset) {
3492
3494
  if (Array.isArray(pluginOrPreset))
@@ -12,6 +12,11 @@ export default defineAction({
12
12
  .describe("Workspace member email addresses to change."),
13
13
  operation: z.enum(["add", "remove"]).describe("Membership operation."),
14
14
  }),
15
+ mcpAnnotations: {
16
+ readOnlyHint: false,
17
+ destructiveHint: true,
18
+ openWorldHint: false,
19
+ },
15
20
  run: async (args, ctx) => {
16
21
  await assertWorkspaceUserGroupManager(ctx?.orgId, ctx?.userEmail);
17
22
  return updateWorkspaceUserGroupMembers({
@@ -7,6 +7,11 @@ export default defineAction({
7
7
  schema: z.object({
8
8
  id: z.string().min(1).describe("User group ID to delete."),
9
9
  }),
10
+ mcpAnnotations: {
11
+ readOnlyHint: false,
12
+ destructiveHint: true,
13
+ openWorldHint: false,
14
+ },
10
15
  run: async ({ id }, ctx) => {
11
16
  await assertWorkspaceUserGroupManager(ctx?.orgId, ctx?.userEmail);
12
17
  const orgId = ctx?.orgId ?? "";
@@ -11,6 +11,11 @@ export default defineAction({
11
11
  .default([])
12
12
  .describe("Workspace member email addresses in this group."),
13
13
  }),
14
+ mcpAnnotations: {
15
+ readOnlyHint: false,
16
+ destructiveHint: true,
17
+ openWorldHint: false,
18
+ },
14
19
  run: async (args, ctx) => {
15
20
  await assertWorkspaceUserGroupManager(ctx?.orgId, ctx?.userEmail);
16
21
  return upsertWorkspaceUserGroup({
@@ -164,9 +164,9 @@ A handful of actions are too consequential to let the agent run on its own, like
164
164
 
165
165
  When `needsApproval` is omitted, behavior is byte-for-byte unchanged. There is no extra cost on the common path.
166
166
 
167
- This works the same way for legacy `parameters`-style actions and for schema-based actions. It also works the same way for the in-app agent, sub-agents, A2A, and MCP callers, because every agent surface routes through the same loop.
167
+ This works the same way for legacy `parameters`-style actions and for schema-based actions. The in-app agent and sub-agents pause in the agent loop. MCP and A2A use their own approval flows.
168
168
 
169
- Calls over the [HTTP API](/docs/http-api) cannot give approval. When a call needs it, the route refuses with a `409` and `errorCode: "approval_required"`, whether the caller holds a bearer token, an API key, an MCP OAuth token, an org service token, or an A2A identity. A service identity can never approve. Only the app's own signed-in UI runs such a call directly, because the person using it is the one approving. A browser call proves it comes from that UI with a short-lived UI capability. A call that claims to be the app without one gets a `403` with `errorCode: "ui_capability_required"`, and the app's client mints the capability and retries once. To have an agent's calls approved, connect it over [MCP](/docs/external-agents) or have it ask in the app's agent chat.
169
+ Direct calls to the [HTTP API](/docs/http-api) cannot provide human approval. The action route runs a gated call only for the proven app UI or the app's MCP directory widget. Other direct HTTP callers receive a `409` with `errorCode: "approval_required"`, and a service identity cannot approve. The shared client sends a short-lived UI capability with signed-in writes. A call without proof receives `403` with `errorCode: "ui_capability_required"`, then the client mints the capability and retries once. A2A tasks use their own approval flow, not this HTTP response. The task pauses until its owner approves, then replays the approved tool call. The local `pnpm action ...` CLI calls `handler.run()` directly and does not evaluate `needsApproval`. Treat this field as an approval flow, not an authorization boundary.
170
170
 
171
171
  ### How the loop pauses {#loop}
172
172
 
@@ -403,12 +403,12 @@ A create action calls neither helper. It only needs to stamp `ownerEmail` (and `
403
403
 
404
404
  The four mechanisms are not interchangeable:
405
405
 
406
- | Mechanism | Question it answers | Applies to |
407
- | --------------------------------- | ----------------------------------------------------- | -------------------------------- |
408
- | `access` | Does the caller hold the declared role or membership? | All six dispatch sites |
409
- | `authorize` | May this caller perform the operation at all? | All six dispatch sites |
410
- | `needsApproval` | Should a human approve this specific permitted call? | Every surface |
411
- | `accessFilter()`/`assertAccess()` | Which rows may this permitted caller see or write? | Inside `run()`, per query or row |
406
+ | Mechanism | Question it answers | Applies to |
407
+ | --------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------- |
408
+ | `access` | Does the caller hold the declared role or membership? | All six dispatch sites |
409
+ | `authorize` | May this caller perform the operation at all? | All six dispatch sites |
410
+ | `needsApproval` | Should a human approve this specific permitted call? | Agent, MCP, A2A. HTTP gates unproven calls. Local CLI bypasses. |
411
+ | `accessFilter()`/`assertAccess()` | Which rows may this permitted caller see or write? | Inside `run()`, per query or row |
412
412
 
413
413
  A restricted write action typically needs both `authorize` and a row check. The first keeps non-coaches out of the operation. The second keeps a coach out of another org's plan. The row check is `assertAccess()`, or `access` when the row's id is an input field. `needsApproval` is a separate axis. It never restricts who may call, only whether the agent may proceed unattended.
414
414
 
@@ -385,14 +385,15 @@ A network drop, a proxy's HTML error page, and a bare status line author no mess
385
385
 
386
386
  ### What each throw produces {#failure-shapes}
387
387
 
388
- | Thrown from `run()` | HTTP status | Response body | Reported to error tracking |
389
- | ----------------------------------------------- | ----------------- | -------------------------------------------- | -------------------------- |
390
- | `fail(msg)` | 400 | `{ error: msg, errorCode: "action_failed" }` | No |
391
- | `fail(msg, { errorCode, statusCode, details })` | your `statusCode` | `{ error, errorCode, details }` | No |
392
- | `new ActionContractError(msg, { errorCode })` | 409 | `{ error, errorCode, details }` | No |
393
- | `new AgentActionStopError(msg)` | 500 | `{ error: msg }` | No |
394
- | `new Error(msg)` | 500 | `{ error: "Internal server error" }` | Yes |
395
- | Input that fails `schema` | 400 | `{ error: "Invalid action parameters..." }` | No |
388
+ | Thrown from `run()` | HTTP status | Response body | Reported to error tracking |
389
+ | ------------------------------------------------------------------ | ----------------- | ---------------------------------------------- | -------------------------- |
390
+ | `fail(msg)` | 400 | `{ error: msg, errorCode: "action_failed" }` | No |
391
+ | `fail(msg, { errorCode, statusCode, details })` | your `statusCode` | `{ error, errorCode, details }` | No |
392
+ | `new ActionContractError(msg, { errorCode })` | 409 | `{ error, errorCode, details }` | No |
393
+ | `new AgentActionStopError(msg)` | 500 | `{ error: msg }` | No |
394
+ | A PostgreSQL deadlock (`40P01`) or serialization failure (`40001`) | 409 | `{ error, errorCode: "transaction_conflict" }` | No |
395
+ | `new Error(msg)` | 500 | `{ error: "Internal server error" }` | Yes |
396
+ | Input that fails `schema` | 400 | `{ error: "Invalid action parameters..." }` | No |
396
397
 
397
398
  `AgentActionStopError` is the one to throw when the agent should end its turn rather than read the failure and try again. `ActionContractError` is what `fail()` raises for you, so reach for it directly only when 409 is the status you want.
398
399
 
@@ -20,7 +20,7 @@ hosting behavior.
20
20
  | `APP_URL` | Optional canonical public origin. Checked ahead of `BETTER_AUTH_URL` when resolving the A2A JWT audience, the OAuth public origin, self-dispatch webhook targets, and generated resource links. Set it explicitly on preview/staging deploys where the request host is unreliable. |
21
21
  | `AGENT_PROD_CODE_EXECUTION` | Optional production code-execution mode: `off` (default), `sandboxed`, or `trusted`. See [Production Code Execution](/docs/actions-agent-tools#production-code-execution). |
22
22
  | `AGENT_NATIVE_SSR_CACHE` | Deployment-wide SSR shell cache policy: unset/`on` keeps the default hard-cache, `off` sends `no-store`, or a duration such as `30s` / `5m` sets a shorter freshness. See [SSR Caching](/docs/ssr-caching). |
23
- | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Optional HTTPS URL of a script loaded with `defer` in the `<head>` of every server-rendered page. Use it for deployment-specific tooling such as an internal feedback widget, without changing app source. Non-HTTPS URLs fail config validation. |
23
+ | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Optional HTTPS URL of a script added to the `<head>` of every server-rendered page. Where the consent banner shows, it waits for analytics consent, like Google Analytics. Use it for deployment-specific tooling such as an internal feedback widget, without changing app source. Non-HTTPS URLs fail config validation. |
24
24
  | `AGENT_NATIVE_ENABLE_KEEP_WARM` | Opt into the Netlify keep-warm scheduled function. Unset by default. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
25
25
  | `AGENT_NATIVE_DISABLE_KEEP_WARM` | Compatibility kill switch for the Netlify keep-warm scheduled function. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
26
26
  | `AGENT_NATIVE_KEEP_WARM_SCHEDULE` | Override the keep-warm cadence with a 5-field cron expression (default `* * * * *` when enabled). An unparseable value fails the build. See [Keep-warm](/docs/netlify#netlify-keep-warm). |
@@ -95,7 +95,7 @@ public app behavior, use the config paths above instead.
95
95
  | `ACCESS_TOKEN` / `ACCESS_TOKENS` | Static bearer fallback for MCP and Connect clients. | One token or a delimited token list; these are not browser auth. |
96
96
  | `AGENT_PROD_CODE_EXECUTION` | Production code-execution policy. | `off`, `sandboxed`, or `trusted`. See [Production Code Execution](/docs/actions-agent-tools#production-code-execution). |
97
97
  | `AGENT_NATIVE_SSR_CACHE` | Deployment-wide public SSR shell cache policy. | Unset/`on`, `off`, or a duration such as `30s` or `5m`. See [SSR Caching](/docs/ssr-caching). |
98
- | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Extra script injected into every server-rendered page head with `defer`. | An absolute `https://` URL; non-HTTPS values fail config validation. |
98
+ | `AGENT_NATIVE_HEAD_SCRIPT_SRC` | Extra script added to every server-rendered page head. Where the consent banner shows, it waits for analytics consent, like Google Analytics. | An absolute `https://` URL; non-HTTPS values fail config validation. |
99
99
  | `AGENT_NATIVE_ENABLE_KEEP_WARM` | Opts into the Netlify keep-warm scheduled function; unset by default. | `1`; see [Keep-warm](/docs/netlify#netlify-keep-warm). |
100
100
  | `AGENT_NATIVE_DISABLE_KEEP_WARM` | Compatibility kill switch for the Netlify keep-warm scheduled function. | `1`; see [Keep-warm](/docs/netlify#netlify-keep-warm). |
101
101
  | `AGENT_NATIVE_KEEP_WARM_SCHEDULE` | Keep-warm cadence override when enabled. | A 5-field cron expression such as `*/5 * * * *`; an unparseable value fails the build. |
@@ -134,15 +134,15 @@ Every design-specific operation is a TypeScript file in
134
134
 
135
135
  ### Motion and shaders
136
136
 
137
- | Action | What it does |
138
- | ------------------------ | ------------------------------------------- |
139
- | `get-motion-timeline` | Read an element's motion timeline |
140
- | `apply-motion-edit` | Add or edit a keyframe on a motion timeline |
141
- | `remove-motion-timeline` | Remove a motion timeline |
142
- | `apply-shader` | Apply a shader effect |
143
- | `apply-shader-fill` | Apply a shader as a fill |
144
- | `preview-shader-fill` | Preview a shader fill before applying it |
145
- | `get-shader` | Read a shader's current parameters |
137
+ | Action | What it does |
138
+ | ------------------------ | ----------------------------------------------------- |
139
+ | `get-motion-timeline` | Read an element's motion timeline |
140
+ | `apply-motion-edit` | Add or edit a keyframe on a motion timeline |
141
+ | `remove-motion-timeline` | Remove a motion timeline |
142
+ | `get-shader` | Inspect native definitions and saved effect manifests |
143
+ | `edit-native-shader` | Apply, edit, approve, or remove native effects |
144
+
145
+ Native WebGPU effects use WGSL. Custom authoring uses `edit-native-shader` with `define-definition`, `get-shader` to read the saved `executionHash`, `approve-definition` with that `expectedExecutionHash`, then `apply` with the exact definition ID/version. Each edit requires `designId`, `fileId`, and the current `expectedVersionHash`. Re-read the file hash after each write. CPU schema validation does not compile GPU code, so verify the Design preview. Previously saved GLSL effects remain renderable and removable.
146
146
 
147
147
  ### Quality {#quality}
148
148
 
@@ -175,9 +175,7 @@ when they apply to the current selection:
175
175
 
176
176
  - **Fill** and **Stroke**: color, gradient, or image paint, with a
177
177
  document color palette to reuse existing colors.
178
- - **Effects**: drop shadow, layer blur, background blur, and a
179
- code-backed shader effect with named sliders (speed, color, center
180
- point) and a Code panel for the raw GLSL.
178
+ - **Effects**: Drop shadow, layer blur, background blur, and native WebGPU effects with editable properties. Shader creation opens the agent chat to author native WGSL. Previously saved GLSL effects remain renderable and removable.
181
179
  - **Position & layout**, **Typography**, **Appearance** (corner radius,
182
180
  blend mode, visibility): the standard per-element property groups.
183
181
  - **Layout** and **Auto layout**: flex-style arrangement for a frame's
@@ -43,6 +43,10 @@ A host counts as local when it has a real working directory, a terminal, and a w
43
43
 
44
44
  On a browser host the skill requires the Agent-Native Dispatch MCP connector (`https://dispatch.agent-native.com/mcp`, OAuth) and calls its `start-workspace-app-creation` action. The host cannot run or inspect the app, so the report stays pending or unverified until the branch Dispatch returns is built. The skill reports what Dispatch actually returned and never invents a branch URL. For a ChatGPT Project, or any host that only exposes MCP, put the skill instructions in the Project instructions or knowledge files.
45
45
 
46
+ ## Local prerequisites
47
+
48
+ On a local host, install Node.js 22.22.0 or newer (which includes npm and npx) and pnpm before starting. Browser hosts use Dispatch and do not run these commands.
49
+
46
50
  ## Sources {#sources}
47
51
 
48
52
  - **Threads.** The last concrete, repeatable job is the product.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.214.0",
3
+ "version": "0.217.0",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -527,6 +527,7 @@
527
527
  "./client/changelog/use-changelog-seen": "./dist/client/changelog/use-changelog-seen.js",
528
528
  "./client/chat-model-groups": "./dist/client/chat-model-groups.js",
529
529
  "./client/client-status-requests": "./dist/client/client-status-requests.js",
530
+ "./client/consent": "./dist/client/consent.js",
530
531
  "./client/context-xray/format": "./dist/client/context-xray/format.js",
531
532
  "./client/dev-overlay/builtins": "./dist/client/dev-overlay/builtins.js",
532
533
  "./client/error-reporting": "./dist/client/error-reporting.js",
@@ -551,6 +552,7 @@
551
552
  "./client/onboarding/first-run-registry": "./dist/client/onboarding/first-run-registry.js",
552
553
  "./client/onboarding/first-run-status": "./dist/client/onboarding/first-run-status.js",
553
554
  "./client/onboarding/use-onboarding": "./dist/client/onboarding/use-onboarding.js",
555
+ "./client/onboarding/use-onboarding-checklist": "./dist/client/onboarding/use-onboarding-checklist.js",
554
556
  "./client/onboarding/use-preview-mode": "./dist/client/onboarding/use-preview-mode.js",
555
557
  "./client/org/hooks": "./dist/client/org/hooks.js",
556
558
  "./client/resources/mcp-connection-resume": "./dist/client/resources/mcp-connection-resume.js",
@@ -600,6 +602,7 @@
600
602
  "./notifications/types": "./dist/notifications/types.js",
601
603
  "./observability/types": "./dist/observability/types.js",
602
604
  "./onboarding/types": "./dist/onboarding/types.js",
605
+ "./onboarding/status": "./dist/onboarding/status.js",
603
606
  "./onboarding/workspace-services": "./dist/onboarding/workspace-services.js",
604
607
  "./onboarding/app-profile-data": "./dist/onboarding/app-profile-data.js",
605
608
  "./org/app-roles": "./dist/org/app-roles.js",
@@ -727,8 +730,8 @@
727
730
  "yaml": "^2.9.0",
728
731
  "yjs": "^13.6.33",
729
732
  "zod": "^4.3.6",
730
- "@agent-native/agentkit": "^0.214.0",
731
- "@agent-native/recap-cli": "^0.5.83"
733
+ "@agent-native/agentkit": "^0.217.0",
734
+ "@agent-native/recap-cli": "^0.5.86"
732
735
  },
733
736
  "devDependencies": {
734
737
  "@ai-sdk/anthropic": "^3.0.71",
@@ -140,6 +140,6 @@ export default defineAction({
140
140
 
141
141
  When the gate is truthy and the call isn't yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. A predicate gates conditionally (e.g. only external recipients) and **fails closed**: a throw is treated as "approval required". It receives its own copy of the prepared snapshot of the validated arguments, defaults applied, and the approval binds to the snapshot's hash, so an approved call runs only with the arguments that were approved (a Date binds by its time). The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's `approvalKey`, and only then does the action run.
142
142
 
143
- Approval is given in the app, so HTTP never grants it. The HTTP action route and the generated Workers entry run a gated call only for the proven app UI (a frontend call from the signed-in user, same origin, holding the short-lived UI capability; `isProvenUiRequest`, the proof `uiOnly` uses) or the app's MCP directory widget. Every other HTTP caller (bearer or API key, MCP OAuth token, org service token, A2A, extension iframe, mobile app) gets `409 approval_required`, and a service identity can never approve. The shared client presents the capability with every write from a signed-in session (minted once per user, reused for nine minutes, never for reads or public pages), so a gated button works on its first request. A call without proof gets `403 ui_capability_required`; the client then re-mints and retries once, which is only the fallback for an expired or rejected capability. Every surface evaluates the gate through `preparedCallNeedsApproval`, so a throwing predicate asks there too. A caller that must run unattended needs a different action, never a bypass of the gate.
143
+ Approval is given in the app, so HTTP never grants it. The HTTP action route and the generated Workers entry run a gated call only for the proven app UI (a frontend call from the signed-in user, same origin, holding the short-lived UI capability; `isProvenUiRequest`, the proof `uiOnly` uses) or the app's MCP directory widget. Every other direct HTTP caller (bearer or API key, MCP OAuth token, org service token, extension iframe, or mobile app) gets `409 approval_required`, and a service identity can never approve. A2A tasks use their separate approval flow. The task pauses until its owner approves, then replays the approved tool call under its approval lease. The shared client presents the capability with every write from a signed-in session (minted once per user, reused for nine minutes, never for reads or public pages), so a gated button works on its first request. A call without proof gets `403 ui_capability_required`; the client then re-mints and retries once, which is only the fallback for an expired or rejected capability. The agent loop, plan mode registry, HTTP action route, generated Workers entry, and MCP dispatch evaluate the gate through `preparedCallNeedsApproval`, so a throwing predicate asks there too. The local `pnpm action ...` CLI calls `handler.run()` directly and does not evaluate `needsApproval`. Treat it as a local development tool, not an approval boundary. A caller that must run unattended needs a different action, never a bypass of the gate.
144
144
 
145
145
  **Keep approvals rare** — the default is off and almost every action should leave it off. The canonical example is Mail's `send-email` (`needsApproval: true`). See the `security` skill and the Human Approval doc.
@@ -140,6 +140,6 @@ export default defineAction({
140
140
 
141
141
  When the gate is truthy and the call isn't yet approved, the loop emits an `approval_required` event and **stops the turn — `run()` never executes**. A predicate gates conditionally (e.g. only external recipients) and **fails closed**: a throw is treated as "approval required". It receives its own copy of the prepared snapshot of the validated arguments, defaults applied, and the approval binds to the snapshot's hash, so an approved call runs only with the arguments that were approved (a Date binds by its time). The human approves via the chat UI's Approve affordance, which re-issues the turn with the call's `approvalKey`, and only then does the action run.
142
142
 
143
- Approval is given in the app, so HTTP never grants it. The HTTP action route and the generated Workers entry run a gated call only for the proven app UI (a frontend call from the signed-in user, same origin, holding the short-lived UI capability; `isProvenUiRequest`, the proof `uiOnly` uses) or the app's MCP directory widget. Every other HTTP caller (bearer or API key, MCP OAuth token, org service token, A2A, extension iframe, mobile app) gets `409 approval_required`, and a service identity can never approve. The shared client presents the capability with every write from a signed-in session (minted once per user, reused for nine minutes, never for reads or public pages), so a gated button works on its first request. A call without proof gets `403 ui_capability_required`; the client then re-mints and retries once, which is only the fallback for an expired or rejected capability. Every surface evaluates the gate through `preparedCallNeedsApproval`, so a throwing predicate asks there too. A caller that must run unattended needs a different action, never a bypass of the gate.
143
+ Approval is given in the app, so HTTP never grants it. The HTTP action route and the generated Workers entry run a gated call only for the proven app UI (a frontend call from the signed-in user, same origin, holding the short-lived UI capability; `isProvenUiRequest`, the proof `uiOnly` uses) or the app's MCP directory widget. Every other direct HTTP caller (bearer or API key, MCP OAuth token, org service token, extension iframe, or mobile app) gets `409 approval_required`, and a service identity can never approve. A2A tasks use their separate approval flow. The task pauses until its owner approves, then replays the approved tool call under its approval lease. The shared client presents the capability with every write from a signed-in session (minted once per user, reused for nine minutes, never for reads or public pages), so a gated button works on its first request. A call without proof gets `403 ui_capability_required`; the client then re-mints and retries once, which is only the fallback for an expired or rejected capability. The agent loop, plan mode registry, HTTP action route, generated Workers entry, and MCP dispatch evaluate the gate through `preparedCallNeedsApproval`, so a throwing predicate asks there too. The local `pnpm action ...` CLI calls `handler.run()` directly and does not evaluate `needsApproval`. Treat it as a local development tool, not an approval boundary. A caller that must run unattended needs a different action, never a bypass of the gate.
144
144
 
145
145
  **Keep approvals rare** — the default is off and almost every action should leave it off. The canonical example is Mail's `send-email` (`needsApproval: true`). See the `security` skill and the Human Approval doc.
@@ -21,25 +21,15 @@ Four phases, in order. Phase 0 comes before any investigation, not after.
21
21
  2. **Fix** what the evidence actually proves, at the owning boundary.
22
22
  3. **Reply** with useful questions, then recap.
23
23
 
24
- Output is fixes. For every unheld in-scope report root this task owns, keep one concise, current same-actor status reply after the latest human message. It names every verified `✅` scope and its evidence, every open scope, and each `🎫` action and owner (or why a mark does not apply). Add and read back root `✅` as soon as direct post-change proof verifies a scope, and root `🎫` as soon as another person or team must act. An `👀` alone never completes the status. Preserve all reaction history, and follow [`slack-reaction-replies.md`](references/slack-reaction-replies.md). Do not reply on held, person-assigned, or `:mag:` items.
25
-
26
- ### Read the root marks as history; use the reply for current status
27
-
28
- - `👀` records this workflow's claim. It does not mean the report is still open.
29
- - `✅` records a scope that passed direct post-change proof. Add it as soon as
30
- any scope passes, even when another scope remains open; name the verified
31
- scope and evidence in the status reply.
32
- - `🎫` records a distinct action another person must take, including a reporter
33
- request. Keep the reaction as history after that action is completed,
34
- answered, or abandoned; the current reply must say whether the action is
35
- still open or historical.
36
- - Every owned root needs one current same-actor reply after the latest human
37
- reply. Reuse it while the disposition and evidence remain current; do not
38
- send a duplicate progress reply on every sweep. The reply names verified
39
- scopes, open scopes, human actions and owners, and why either `✅` or `🎫` is
40
- absent. An eye-only root is correct when no scope is verified and no separate
41
- human action is pending; say whether the next step is this workflow's
42
- investigation or no further action.
24
+ Output is fixes. For every unheld in-scope report root this task owns, keep one
25
+ current same-actor status reply after the latest human message. Write one short
26
+ sentence in plain, non-technical language. Say what changed. Use `🎫` only for
27
+ unresolved work; when you use it, briefly say what still needs investigation or
28
+ what action is needed, and name its owner when known. Do not mention or explain
29
+ absent reactions. Keep scope details and proof in the internal ledger. Add and
30
+ read back root reactions as soon as their proof bar passes, preserve reaction
31
+ history, and follow [`slack-reaction-replies.md`](references/slack-reaction-replies.md).
32
+ Do not reply on held, person-assigned, or `:mag:` items.
43
33
 
44
34
  ## Slack channels and ownership
45
35
 
@@ -133,11 +123,13 @@ source window, the three matching owned-mark searches, and older roots linked
133
123
  by in-window replies. For every unheld owned root, compare the latest human
134
124
  message, current status reply, verified scopes, open scopes, and root marks.
135
125
  Add and read back `✅` for each newly verified scope and `🎫` for each distinct
136
- pending human action; the status reply must follow the latest human message and
137
- name current evidence, remaining work, and owners. An `👀` with a verified
138
- scope missing `✅`, a pending human action missing `🎫`, or no current status is
139
- unfinished. Finish the complete bounded set once, then stop; do not chase
140
- unrelated historical marks.
126
+ pending human action; keep evidence, scopes, and full actions/owners in the
127
+ internal ledger. The status reply must follow the latest human message and use
128
+ the concise reply rule above: say what changed, and when `🎫` applies, briefly
129
+ name the unresolved action and its owner when known. A verified scope missing
130
+ `✅`, a pending human action missing `🎫`, or no current status is unfinished.
131
+ Finish the complete bounded set once, then stop; do not chase unrelated
132
+ historical marks.
141
133
 
142
134
  Split reports into distinct scopes. Add root `✅` as soon as any named scope
143
135
  passes direct post-change proof, even while its PR is open; say **Verified
@@ -146,9 +138,10 @@ proof. Add root `🎫` for each distinct unfinished action another human must ta
146
138
  including a requested reporter URL, access grant, evidence, or clarification.
147
139
  The mark tracks an outstanding human action, not an accepted team handoff.
148
140
  Record reporter requests in `reporterRequests[]`, separately from
149
- team/engineering `handoffs[]`. Enumerate each verified scope, open scope,
150
- reporter request, and handoff in the status reply; explain any absent mark. Keep
151
- marks after completion and never remove them. For a closed reporter request,
141
+ team/engineering `handoffs[]`. Keep verified scopes, open scopes, reporter
142
+ requests, and handoffs in the internal ledger; keep the Slack reply focused on
143
+ the current outcome and any `🎫` follow-up. Keep marks after completion and
144
+ never remove them. For a closed reporter request,
152
145
  preserve its request and closure evidence in the historical ticket record; see
153
146
  [`slack-reaction-replies.md`](references/slack-reaction-replies.md).
154
147
 
@@ -382,29 +375,22 @@ instruction or prompt exception.
382
375
  Thank issue reporters for opening issues and Slack reporters for sharing.
383
376
  Before posting, inspect the full thread and follow the one-reply gate in
384
377
  `address-feedback-with-replies` and the [Slack reply reference](references/slack-reaction-replies.md):
385
- send one concise disposition covering done, remaining, and next action/owner.
386
- Do not reply again to announce merge, publication, or live beta; answer direct
387
- reporter follow-ups. End Slack replies with `this was sent from a bot.`.
388
-
389
- Reporter-facing replies are one or two sentences: the change or question, its limit, and the next step. Do not explain workflow mechanics, ledgers, or external tracker tickets. Never send **Open**/**pending** or a symptom recap. Ask for reporter input only when it changes the next step; never request supplied evidence or internal access. Keep hashes, branches, CI, publisher, and run details in the recap.
390
-
391
- Every root this actor marks with `👀`, `✅`, or `🎫` also needs the current
392
- same-actor status reply required by the Slack reaction reference. One concise
393
- reply may serve both purposes when it answers the reporter and records the
394
- current disposition, verified/open scopes, owner/action, and any reason a mark
395
- is absent. This status requirement takes precedence over the reporter-facing
396
- brevity rule only for those facts; do not explain ledger mechanics or external
397
- tracker tickets. A Slack `🎫` reaction tracks a distinct human action, not an
398
- external ticket, and remains as history after the action closes. Never imply
399
- that an external ticket was created or assigned.
400
-
401
- Keep publisher and beta checks in the internal recap after the disposition;
402
- they do not trigger a second reporter reply.
403
-
404
- ### After a PR merges
405
-
406
- Track publisher state and beta verification in the internal recap. Do not send
407
- a routine post-merge reporter reply; answer only a direct reporter follow-up.
378
+ send one short sentence in plain, non-technical language, then end with the
379
+ exact bot disclosure `this was sent from a bot.` Say what changed. Use `🎫`
380
+ only for unresolved work; when it is used, briefly say what still needs
381
+ investigation or action and name its owner when known. Do not explain absent
382
+ reactions or mention a closed, historical `🎫`. Keep hashes, branches, CI,
383
+ publisher details, and proof in the internal recap. Never explain workflow
384
+ mechanics or external tracker tickets in Slack. Never send **Open**/**pending**
385
+ or a symptom recap. Ask for reporter input only when it changes the next step.
386
+
387
+ Every root this actor marks with `👀`, `✅`, or `🎫` also needs a current
388
+ same-actor status reply after the latest human reply. One concise reply can
389
+ answer the reporter and record the disposition. Keep verified scopes, open
390
+ scopes, reaction history, and evidence in the internal ledger; do not enumerate
391
+ them or explain absent reactions in Slack. A Slack `🎫` reaction tracks a
392
+ distinct human action, not an external ticket, and remains as history after the
393
+ action closes. Never imply that an external ticket was created or assigned.
408
394
 
409
395
  For a fixed behavior with a Slack `🎫` handoff, state the done behavior and
410
396
  remaining action/owner separately; don't imply the fixed scope is open. The
@@ -453,36 +439,6 @@ otherwise draft the reply, leave the feedback unresolved, and link it in the
453
439
  recap. This exception is only for PR review feedback, not proactive PR comments
454
440
  or issue comments.
455
441
 
456
- ## Publishing
457
-
458
- Use this worktree's branch. Batch fixes with one
459
- `corepack pnpm ship:push -m "<specific fix>"`; each head reruns CI. Sync
460
- `origin/main` only for GitHub conflicts during review-only work. If the same
461
- task is already running an explicitly authorized `/ship`, follow that skill's
462
- safe-sync rule for a confirmed required-check fix on `origin/main`; do not ask
463
- for another approval. Behind/pending alone never justify syncing.
464
-
465
- Use `/ship` for PR ownership, push, and merge checks. Never push to another
466
- person's PR without explicit authorization for that exact PR in this request.
467
- Push-only authorization means `ship_mode=ready-only`; merging requires separate
468
- authorization for that PR. Without push authorization, hand off as pending.
469
- Carry feedback evidence and dispositions into PRs; reference only issues the
470
- PR fixes.
471
- Keep source-tested, built, deployed, and observed-live claims separate.
472
-
473
- Carry exact tracker row ids and the reproduction ledger into the PR or release
474
- recap; tracker status is not shipping evidence. Mark each row independently: a
475
- reaction, checkmark, or "reviewed" cannot cover multiple rows, including
476
- expected, docs-owned, cross-team, or duplicate items. Link each source/docs
477
- change to its exact PR or commit, and each non-coding disposition to its
478
- evidence or owner.
479
-
480
- If no fix is verified, recap why shipping did not start. Unavailable connectors
481
- and external failures are not shipping blockers.
482
- While waiting, **Clarification needed** stays open with `👀` and no `✅`; it
483
- must not block independent fixes unless it could affect a PR change. Later runs
484
- skip the eye under the ownership gate.
485
-
486
442
  ## Recap
487
443
 
488
444
  Every eligible item gets a row. Report gated skips by count only, without