@agent-native/core 0.214.0 → 0.216.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 (161) 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/application-state/store.d.ts +5 -0
  27. package/dist/application-state/store.js +26 -0
  28. package/dist/chat-threads/schema-migrations.js +17 -0
  29. package/dist/chat-threads/store.d.ts +21 -1
  30. package/dist/chat-threads/store.js +223 -41
  31. package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
  32. package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
  33. package/dist/cli/templates-meta.js +14 -0
  34. package/dist/client/analytics.js +167 -17
  35. package/dist/client/chat/agentkit-agent-native.js +79 -3
  36. package/dist/client/chat/agentkit-protocol.js +80 -42
  37. package/dist/client/chat/runtime.d.ts +5 -1
  38. package/dist/client/chat/runtime.js +46 -3
  39. package/dist/client/consent.d.ts +36 -0
  40. package/dist/client/consent.js +283 -0
  41. package/dist/client/review/use-review.d.ts +2 -0
  42. package/dist/client/review/use-review.js +28 -1
  43. package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
  44. package/dist/client/sharing/useResourceAccessGate.js +9 -1
  45. package/dist/client/use-chat-thread-list.d.ts +2 -0
  46. package/dist/client/use-chat-thread-list.js +12 -2
  47. package/dist/client/use-chat-threads.d.ts +1 -0
  48. package/dist/client/use-chat-threads.js +2 -0
  49. package/dist/collab/awareness.d.ts +2 -2
  50. package/dist/collab/routes.d.ts +2 -2
  51. package/dist/collab/struct-routes.d.ts +1 -1
  52. package/dist/connections/catalog.d.ts +5 -5
  53. package/dist/connections/catalog.js +22 -3
  54. package/dist/data-widgets/index.d.ts +36 -2
  55. package/dist/data-widgets/index.js +94 -6
  56. package/dist/db/migrations.js +4 -1
  57. package/dist/db/schema-snapshot.generated.js +8 -1
  58. package/dist/feature-flags/actions/set-feature-flag.js +5 -0
  59. package/dist/feature-flags/index.d.ts +1 -1
  60. package/dist/feature-flags/index.js +1 -1
  61. package/dist/feature-flags/store.d.ts +12 -0
  62. package/dist/feature-flags/store.js +79 -7
  63. package/dist/file-upload/actions/manage-file-storage.js +5 -0
  64. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  65. package/dist/file-upload/actions/upload-image.js +5 -0
  66. package/dist/history/actions/create-resource-version.js +5 -0
  67. package/dist/history/actions/restore-resource-version.js +5 -0
  68. package/dist/ingestion/index.d.ts +1 -1
  69. package/dist/ingestion/index.js +1 -1
  70. package/dist/ingestion/pptx.d.ts +11 -0
  71. package/dist/ingestion/pptx.js +81 -1
  72. package/dist/integrations/actions/manage-messaging-channel.js +5 -0
  73. package/dist/jobs/scheduler.js +17 -1
  74. package/dist/labs/actions/set-lab.js +5 -0
  75. package/dist/localization/actions/set-localization-preference.js +5 -0
  76. package/dist/observability/actions/save-observability-instruction-update.js +5 -0
  77. package/dist/observability/actions/save-observability-review-summary.js +5 -0
  78. package/dist/progress/routes.d.ts +1 -1
  79. package/dist/provider-api/actions/custom-provider-registration.d.ts +18 -18
  80. package/dist/provider-api/actions/provider-api.d.ts +14 -14
  81. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  82. package/dist/provider-api/index.js +9 -2
  83. package/dist/review/actions/consume-review-feedback.js +5 -0
  84. package/dist/review/actions/create-review-comment.js +5 -0
  85. package/dist/review/actions/delete-review-comment.js +5 -0
  86. package/dist/review/actions/react-to-review-comment.js +5 -0
  87. package/dist/review/actions/reply-review-comment.js +5 -0
  88. package/dist/review/actions/resolve-review-thread.js +5 -0
  89. package/dist/review/actions/send-review-thread-to-agent.js +5 -0
  90. package/dist/review/actions/set-review-status.js +5 -0
  91. package/dist/review/actions/set-review-thread-muted.js +5 -0
  92. package/dist/review/actions/set-review-thread-unread.js +5 -0
  93. package/dist/review/actions/set-review-threads-unread.js +5 -0
  94. package/dist/review/actions/update-review-comment-anchor.js +5 -0
  95. package/dist/review/actions/update-review-comment.js +5 -0
  96. package/dist/review/suggestions/actions.js +60 -21
  97. package/dist/review/suggestions/store.d.ts +2 -0
  98. package/dist/review/suggestions/store.js +28 -0
  99. package/dist/secrets/actions/delete-api-key.js +5 -0
  100. package/dist/secrets/routes.d.ts +6 -6
  101. package/dist/server/agent-chat/context-tools.js +63 -2
  102. package/dist/server/agent-chat-plugin.d.ts +2 -0
  103. package/dist/server/agent-chat-plugin.js +242 -54
  104. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  105. package/dist/server/agent-engine-default-model-route.d.ts +2 -2
  106. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  107. package/dist/server/application-state-maintenance.d.ts +2 -0
  108. package/dist/server/application-state-maintenance.js +2 -0
  109. package/dist/server/attribution.d.ts +14 -0
  110. package/dist/server/attribution.js +62 -2
  111. package/dist/server/auth.js +7 -0
  112. package/dist/server/consent-route.d.ts +41 -0
  113. package/dist/server/consent-route.js +102 -0
  114. package/dist/server/first-touch-route.d.ts +39 -0
  115. package/dist/server/first-touch-route.js +115 -0
  116. package/dist/server/index.d.ts +1 -0
  117. package/dist/server/index.js +1 -0
  118. package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
  119. package/dist/server/queued-submission-inbox-drain.js +12 -0
  120. package/dist/server/request-origin.d.ts +6 -0
  121. package/dist/server/request-origin.js +12 -0
  122. package/dist/settings/org-settings.d.ts +2 -1
  123. package/dist/settings/org-settings.js +4 -1
  124. package/dist/settings/store.d.ts +8 -0
  125. package/dist/settings/store.js +14 -5
  126. package/dist/shared/consent.d.ts +31 -0
  127. package/dist/shared/consent.js +145 -0
  128. package/dist/shared/first-touch-persistence.d.ts +31 -0
  129. package/dist/shared/first-touch-persistence.js +53 -0
  130. package/dist/sharing/actions/set-resource-visibility.js +5 -0
  131. package/dist/sharing/actions/share-resource.js +5 -0
  132. package/dist/sharing/actions/unshare-resource.js +5 -0
  133. package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  134. package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  135. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  136. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  137. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  138. package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  139. package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  140. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
  141. package/dist/triggers/actions/manage-automation.d.ts +1 -1
  142. package/dist/usage/actions/get-usage-metrics.js +27 -4
  143. package/dist/usage/actions/manage-usage-alert.js +5 -0
  144. package/dist/vite/client.js +8 -6
  145. package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
  146. package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
  147. package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
  148. package/docs/content/actions-access-control.mdx +8 -8
  149. package/docs/content/actions-defining.mdx +9 -8
  150. package/docs/content/template-design-developers.mdx +9 -9
  151. package/docs/content/template-design-features.mdx +1 -3
  152. package/docs/content/turn-into-app.mdx +4 -0
  153. package/package.json +4 -3
  154. package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  155. package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  156. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  157. package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  158. package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  159. package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  160. package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  161. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
@@ -13,53 +13,35 @@ record as history; the root remains held without a thread read or status reply.
13
13
  Capture
14
14
  the exact Slack actor ID used by the connected tool at sweep start. A mark is
15
15
  owned by this task only when its reaction owner ID matches that actor ID. Each
16
- unheld owned root needs a current disposition and a matching status reply by
17
- that same actor under that same parent, even when the root has only `✅` or `🎫`. A
18
- same-run fix gets its final reply after verification; continuing work gets a
19
- concrete progress reply. An earlier generic “taking a look” does not satisfy
20
- this update. If an existing reply already names the exact canonical disposition
21
- label and includes its recorded evidence verbatim, read it back and record its
22
- timestamp and author ID instead of duplicating it. Do not accept a vague or
23
- negated substring such as `Not fixed` as the `Fixed` label; reject the whole
24
- reply if a `Fixed` label is later contradicted by a claim that the scope remains
25
- not fixed, unfixed, or broken. Use `Partially fixed` while any distinct scope
26
- remains unfinished or a human/team handoff is still `unassigned` or `accepted`.
27
- A completed handoff is retained history, not an open follow-up.
28
- This is one current status reply per owned root, not a reply on every sweep.
29
- Reuse the existing same-actor reply while its disposition and evidence remain
30
- current; send an update when either materially changes. For a recent
31
- unanswered reporter question, reuse the existing same-actor question/update as
32
- the status reply when it states the disposition and evidence. If it does not,
33
- post at most one concise status update that points to the existing unanswered
34
- question without asking it again; then wait silently. Do not send another
35
- question or progress ping before the four-day rule below. When a disposition
36
- includes human handoffs, the status reply must name each handoff's recorded
37
- owner and action; include its scope when the report context does not make it
38
- clear.
16
+ unheld owned root needs a current same-actor status reply under the same parent.
17
+ Reuse it while the disposition remains current; send one short update when it
18
+ materially changes. Write one short sentence in plain, non-technical language,
19
+ then end with the exact bot disclosure
20
+ `this was sent from a bot.` Say what changed. Use `🎫` only for unresolved
21
+ work; when it is used, briefly say what still needs investigation or action and
22
+ name its owner when known. Do not explain absent reactions or mention a closed,
23
+ historical `🎫`. Keep scope, evidence, and handoff details in the internal
24
+ ledger.
39
25
 
40
- Interpret the three root reactions independently from the current disposition:
26
+ Do not send a routine second reply just to announce a merge or publication.
41
27
 
42
- - `👀` is a permanent claim/history mark, not an open/closed indicator.
43
- - `✅` is permanent history for named scopes that passed direct post-change
44
- proof. Add it as soon as any scope passes; do not wait for other scopes or
45
- merge. Keep it if later evidence changes the scope's status, and explain the
46
- historical mark in the current reply and inventory.
47
- - `🎫` is permanent history for a distinct human action, including an
48
- unassigned team action or reporter request. Keep it after completion,
49
- answer, or four-day abandonment; label it historical in the current reply
50
- and inventory when it no longer blocks progress.
28
+ For a recent unanswered reporter question, reuse the existing same-actor
29
+ question/update as the status reply when it still reflects the disposition. If
30
+ it does not, post at most one concise update that points to the question
31
+ without asking it again; then wait silently. Do not send another question or
32
+ progress ping before the four-day rule below. An evidence-only addendum or
33
+ correction is not a current status; edit it into a concise disposition when
34
+ possible, or send one status after the latest human reply.
51
35
 
52
- The current status reply is the source for whether work remains open. When a
53
- root has only `👀`, say that no scope has passed the proof bar for `✅`, whether
54
- the next step belongs to this workflow, and why no separate human action needs
55
- `🎫`. Reuse a current reply rather than posting again on every sweep.
56
-
57
- An evidence-only addendum or a correction is not a current status. When your
58
- newest own reply is one of those, edit that reply into the full canonical
59
- disposition when possible; otherwise send one final status after the latest
60
- human reply. Name the verified `✅` scope or why none applies, every open scope,
61
- and each `🎫` action with its owner or why none applies. Keep the exact bot
62
- disclosure and read the visible final reply and root reactions back.
36
+ Keep full proof, scope, and handoff details in the internal ledger. When an
37
+ active `🎫` action remains, record its brief plain-language summary as
38
+ `statusReply.pendingActionSummary` and include that summary in the short reply.
39
+ When `unfinishedScopes` is nonempty, also record a brief
40
+ `statusReply.unfinishedScopeSummary` that names remaining work using wording
41
+ grounded in its recorded scope or evidence and says it is still open; include it
42
+ in the public reply even when there is no active `🎫`.
43
+ Do not explain absent reactions or list every scope. End with the exact bot
44
+ disclosure and read the visible reply and root reactions back.
63
45
 
64
46
  When editing an ordinary Slack reply, pass its visible body as
65
47
  `message.markdown_text` to `slack_edit_message`; `message.text` is a fallback
@@ -166,7 +148,8 @@ then immediately update and read back each applicable root reaction before
166
148
  advancing to the next report. Add `✅` as soon as any reported scope passes the
167
149
  direct post-change proof bar, including before merge; use
168
150
  **Partially fixed** for the overall disposition when another scope remains,
169
- and describe both scopes separately in the reply. Do not wait for an entire
151
+ and record both scopes in the internal ledger. Keep the reply short; do not
152
+ wait for an entire
170
153
  multi-symptom report to be resolved before checking off its verified scope.
171
154
  Keep all existing reactions after scopes close. Post the final disposition and
172
155
  read back the final reply and reactions; the status shows closure while the
@@ -174,7 +157,7 @@ eye remains as history. Never remove or clean up any reaction. An open PR can
174
157
  earn `✅` as soon as the relevant
175
158
  `verifying-changes` proof bar passes. During that period, `✅` marks the
176
159
  verified scope and `👀` may remain whether or not another scope or merge is
177
- open; the marks are independent. The current disposition says what remains.
160
+ open; the marks are independent. The internal ledger records what remains.
178
161
  For UI behavior, a focused
179
162
  regression qualifies only if it exercises the changed component and asserts the
180
163
  reported visible result or persisted state; callback-only assertions, mocked
@@ -182,24 +165,28 @@ children, class-name checks, and source inspection do not. For clipping,
182
165
  wrapping, contrast, or alignment, inspect rendered geometry at the reported
183
166
  viewport or replay the flow in the running app. Use an app/preview replay when
184
167
  the regression does not meet that bar. For non-UI scopes, use the area-specific
185
- action, query, or test proof. Say that merge or rollout is still pending; the
186
- checkmark records the verified scope and does not claim it is shipped or live.
168
+ action, query, or test proof. Record merge or rollout state in the internal
169
+ ledger; the checkmark records verified scope and does not claim it is shipped
170
+ or live.
187
171
  Before leaving each report, compare verified scopes and human/team handoffs
188
172
  with a fresh root-reaction read. Ensure one `✅` is present when any scope passed the
189
173
  proof bar and one `🎫` whenever any distinct unfinished action requires another
190
174
  person or team to act, even before ownership is assigned or accepted. Keep the
191
175
  mark as history after completion; read back each changed root reaction and
192
- verify its owner. If either mark does
193
- not apply, the current reply must say why. Emoji text in a reply is not a
176
+ verify its owner. Record why a mark is absent in the internal ledger. Never
177
+ explain absent `👀` or `✅` in a Slack reply. Emoji text in a reply is not a
194
178
  reaction. Preserve every existing reaction. If later proof invalidates a prior
195
179
  checkmark, move that scope out of active `fixedScopes[]` and add a
196
180
  `historicalReactionMarks[]` entry with `emoji`, `scope`, `reason`, and the exact
197
- prior `previousStatus`; the current status and reaction decision must explain
198
- why the retained mark is historical. If the owner withdraws an accepted action
181
+ prior `previousStatus`; keep the explanation in the internal ledger rather
182
+ than the Slack reply. If the owner withdraws an accepted action
199
183
  tracked by `🎫`, also preserve the exact earlier accepted `handoff` and owner
200
- `withdrawalReply`, move it out of current `handoffs[]`, and explain the history
201
- in the current status. The checker validates these records against the captured
202
- thread; never remove or clean up a reaction.
184
+ `withdrawalReply`, and move it out of current `handoffs[]`. Keep that history
185
+ in the internal ledger. Preserve the recorded evidence and historical action in
186
+ the ledger; do not repeat a closed handoff in Slack unless a current action
187
+ remains. When a recorded action has a validated `publicActionSummary`, it may
188
+ be used for a current `🎫` summary. The checker validates it against the
189
+ recorded action and captured thread; never remove or clean up a reaction.
203
190
  Add `🎫` for each distinct unfinished team or engineering action that another
204
191
  person or team must perform outside this workflow, whether or not a named
205
192
  person has accepted it or an external tracker ticket exists. Record each such
@@ -245,8 +232,9 @@ Keep its original `scope`, `action`, `requestReply`, and ticket-bearing
245
232
  `resolution: "answered"` and include the exact human `closureReply` from the
246
233
  same thread. For an unanswered request,
247
234
  set `resolution: "abandoned_no_answer"` only after four days with no later human
248
- reply, and omit `closureReply`. The current status must identify the historical
249
- action and explain why its mark remains. Link an external tracker ticket only
235
+ reply, and omit `closureReply`. The internal ledger must identify the
236
+ historical action and explain why its mark remains; do not explain it in the
237
+ Slack reply unless a current follow-up remains. Link an external tracker ticket only
250
238
  if one already exists; do not create or promise one without authorization. If a
251
239
  human later refuses the accepted action, preserve `🎫` as history and update
252
240
  the status with the refusal and blocker.
@@ -282,10 +270,11 @@ do not send a second owner update. If another task owns it or ownership is
282
270
  unclear, preserve the eye, record the source in the ledger, and stop. Keep
283
271
  distinct scopes and their status clear.
284
272
 
285
- Compare each reported symptom with the evidence. State what is fixed and what
286
- is not. Use one root `✅` when at least one fixed scope is verified; it covers every
287
- verified scope listed in `fixedScopes[]`, which the status must name with its
288
- proof. Use one root `🎫` whenever at least one distinct unfinished action
273
+ Compare each reported symptom with the evidence. If the report is only partly
274
+ fixed, say so briefly and keep the scope details in the ledger. Use one root
275
+ `✅` when at least one fixed scope is verified; it covers every
276
+ verified scope listed in `fixedScopes[]`, which the internal ledger must name
277
+ with its proof. Use one root `🎫` whenever at least one distinct unfinished action
289
278
  requires another person to act; it covers the actions listed in `handoffs[]`
290
279
  and active requests in `reporterRequests[]`. Handoffs include unassigned
291
280
  actions and completed actions whose evidence and `status: "completed"` remain
@@ -299,18 +288,6 @@ team handoff also gets `🎫`. Do not create or promise an external tracker
299
288
  ticket without authorization. Never imply a
300
289
  partial fix resolved the whole report.
301
290
 
302
- For beta app fixes, check the matching merge-triggered publisher and keep
303
- details in the recap. Do not post a routine second reply for merge or rollout.
304
- If a reporter-facing reply is otherwise due, link the merged PR and state the
305
- beta status in plain language. Say it is live only after checking it there. If
306
- publication is pending, say it should follow soon without an exact date. If
307
- the app or behavior cannot be checked, name that limit. If the publisher is
308
- missing or failed, give no ETA and name the next action and owner. Keep hashes,
309
- branch names, CI, workflow details, and run IDs out of reporter replies. For
310
- package work, distinguish the source PR from any release PR and registry proof;
311
- source merge alone does not establish publication. Give no ETA for a pending
312
- package release.
313
-
314
291
  For every reply in each final full-thread snapshot, record a read-back of the
315
292
  workflow reactions on that reply. If the connector shows `👀`, `✅`, or `🎫`,
316
293
  call `slack_get_reactions` for the reply's own timestamp and record exact owner
@@ -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.
@@ -13,15 +13,16 @@ metadata:
13
13
 
14
14
  # Turn Into App
15
15
 
16
- Give a proven workflow the face of an app and the brain of an agent. The first
17
- screen shows the user's world, populated. Controls on those objects hand work
18
- to the in-app agent, the object shows it is working, and the result lands back
19
- in the UI. A form under a stepper bar is the failure to prevent.
16
+ Give a proven workflow an Agent-Native app face and agent brain. Start with
17
+ populated domain screens. Object controls send work to the agent; the object
18
+ shows progress and receives the result. Avoid form-under-stepper layouts.
20
19
 
21
20
  ## Host, source, and when to ask
22
21
 
23
22
  ### Classify the host
24
23
 
24
+ - Local scaffolding needs Node.js 22.22.0 or newer (including npm/npx) and
25
+ pnpm.
25
26
  - **Local host**: a terminal, a filesystem, and a target checkout (Claude Code,
26
27
  Codex, Cursor, or an Agent-Native agent that can edit files). Build the app in
27
28
  that checkout with steps 1-6. Never call `start-workspace-app-creation` or
@@ -105,9 +106,8 @@ opens on a mapping or setup screen.
105
106
 
106
107
  ## Workflow
107
108
 
108
- Copy this checklist and keep it current. Pace: aim for about 45 minutes; note
109
- the start time (`date`), and if 35 minutes have passed when the review starts,
110
- run one pass and list the open criteria.
109
+ Copy and update this checklist. Aim for 45 minutes; note the start time
110
+ (`date`). If review starts after 35 minutes, run one pass and list open criteria.
111
111
 
112
112
  ```text
113
113
  - [ ] 0 Host classified, source picked
@@ -160,13 +160,12 @@ without waiting.
160
160
 
161
161
  ### 3. Create the real scaffold
162
162
 
163
- Before the first command, say once what the run executes (install, scaffold,
164
- checks, a dev server, a headless browser), so permission prompts do not read
165
- as trouble.
163
+ Before the first command, name the steps (install, scaffold, checks, dev server,
164
+ headless browser) and estimate work time from the source and host. Separate
165
+ external setup waits, so delays are expected.
166
166
 
167
- Choose a short slug and never overwrite an existing app. For a standalone app,
168
- run from the directory that should contain it (the app is its own git
169
- repository; say so when it sits inside another checkout):
167
+ Choose a short slug and never overwrite an app. Run standalone creation from
168
+ its parent directory, noting that the nested app is its own Git repository:
170
169
 
171
170
  ```bash
172
171
  npx --yes @agent-native/core@latest create <slug> --standalone --template chat
@@ -182,11 +181,10 @@ from the workspace root:
182
181
  pnpm exec agent-native add-app <slug> --template chat
183
182
  ```
184
183
 
185
- Read the generated `AGENTS.md`, and its `build-an-app` skill when the scaffold
186
- ships one. Where that guidance skips the design record, screenshots, or build,
187
- leaves `DESIGN.md` alone, says not to set `AUTH_DISABLED`, or says to stop the
188
- dev server, this skill's steps win for this run. Use another first-party
189
- template only when it materially fits.
184
+ Read the generated `AGENTS.md` and any `build-an-app` skill. This skill
185
+ overrides guidance that skips the design record, screenshots, or build; leaves
186
+ `DESIGN.md` unchanged; omits `AUTH_DISABLED` or says not to set it; or stops
187
+ the dev server. Use another first-party template only if it materially fits.
190
188
 
191
189
  If a scaffold or install step fails, times out (no output for 5 minutes), or is
192
190
  denied, the app does not exist yet. Retry once where a retry could help, then
@@ -195,6 +193,10 @@ hand-build the app in another stack, edit a pinned dependency version to force
195
193
  an install, or continue in a half-created directory; a workaround the user
196
194
  requests is named in the report.
197
195
 
196
+ Before resuming, inspect the target and verify completed stages. Tell the user
197
+ what exists, the next stage, and estimated active work; resume at the first
198
+ unverified stage without rerunning scaffolding or replacing completed work.
199
+
198
200
  Then save the brief as `docs/brief.md`, append the domain surface's design to
199
201
  `DESIGN.md` (UI direction guide, section 4), and follow
200
202
  [the run and deploy guide](references/local-run-and-deploy.md) to set
@@ -93,6 +93,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
93
93
  previouslyEnabled?: undefined;
94
94
  requestedEnabled?: undefined;
95
95
  } | {
96
+ scope?: undefined;
96
97
  enabled?: undefined;
97
98
  nextRun?: undefined;
98
99
  created?: undefined;
@@ -100,7 +101,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
100
101
  resourceId: string;
101
102
  name: string;
102
103
  updated?: undefined;
103
- scope?: undefined;
104
104
  triggerType?: undefined;
105
105
  event?: undefined;
106
106
  schedule?: undefined;
@@ -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, which belong to 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("Only organization owners and admins can look up another person's usage with get-usage-metrics. Usage, credits, or activity for customers, accounts, or companies belongs to the app that owns that data (see <relevant-apps> or run describe-workspace-apps with a query).", { 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. get-usage-metrics only covers this workspace's own agent usage; usage, credits, or activity for customers, accounts, or companies belongs to the app that owns that data (see <relevant-apps> or run describe-workspace-apps with a query).`, { 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
 
@@ -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.216.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",
@@ -727,8 +728,8 @@
727
728
  "yaml": "^2.9.0",
728
729
  "yjs": "^13.6.33",
729
730
  "zod": "^4.3.6",
730
- "@agent-native/agentkit": "^0.214.0",
731
- "@agent-native/recap-cli": "^0.5.83"
731
+ "@agent-native/agentkit": "^0.216.0",
732
+ "@agent-native/recap-cli": "^0.5.85"
732
733
  },
733
734
  "devDependencies": {
734
735
  "@ai-sdk/anthropic": "^3.0.71",