@agent-native/core 0.213.1 → 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 (169) 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/appearance/actions/get-theme-family.d.ts +8 -0
  27. package/dist/appearance/actions/get-theme-family.js +38 -0
  28. package/dist/appearance/actions/set-theme-family.d.ts +7 -0
  29. package/dist/appearance/actions/set-theme-family.js +33 -0
  30. package/dist/appearance/theme-family.d.ts +13 -0
  31. package/dist/appearance/theme-family.js +38 -0
  32. package/dist/application-state/store.d.ts +5 -0
  33. package/dist/application-state/store.js +26 -0
  34. package/dist/chat-threads/schema-migrations.js +17 -0
  35. package/dist/chat-threads/store.d.ts +21 -1
  36. package/dist/chat-threads/store.js +223 -41
  37. package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
  38. package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
  39. package/dist/cli/templates-meta.js +14 -0
  40. package/dist/client/analytics.js +167 -17
  41. package/dist/client/chat/agentkit-agent-native.js +79 -3
  42. package/dist/client/chat/agentkit-protocol.js +80 -42
  43. package/dist/client/chat/runtime.d.ts +5 -1
  44. package/dist/client/chat/runtime.js +46 -3
  45. package/dist/client/consent.d.ts +36 -0
  46. package/dist/client/consent.js +283 -0
  47. package/dist/client/review/use-review.d.ts +2 -0
  48. package/dist/client/review/use-review.js +28 -1
  49. package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
  50. package/dist/client/sharing/useResourceAccessGate.js +9 -1
  51. package/dist/client/theme-family.d.ts +35 -0
  52. package/dist/client/theme-family.js +223 -0
  53. package/dist/client/theme.d.ts +1 -1
  54. package/dist/client/theme.js +5 -2
  55. package/dist/client/ui/index.d.ts +1 -0
  56. package/dist/client/ui/index.js +1 -0
  57. package/dist/client/use-chat-thread-list.d.ts +2 -0
  58. package/dist/client/use-chat-thread-list.js +12 -2
  59. package/dist/client/use-chat-threads.d.ts +1 -0
  60. package/dist/client/use-chat-threads.js +2 -0
  61. package/dist/connections/catalog.d.ts +5 -5
  62. package/dist/connections/catalog.js +22 -3
  63. package/dist/data-widgets/index.d.ts +374 -5
  64. package/dist/data-widgets/index.js +242 -11
  65. package/dist/db/migrations.js +4 -1
  66. package/dist/db/schema-snapshot.generated.js +8 -1
  67. package/dist/feature-flags/actions/set-feature-flag.js +5 -0
  68. package/dist/feature-flags/index.d.ts +1 -1
  69. package/dist/feature-flags/index.js +1 -1
  70. package/dist/feature-flags/store.d.ts +12 -0
  71. package/dist/feature-flags/store.js +79 -7
  72. package/dist/file-upload/actions/manage-file-storage.js +5 -0
  73. package/dist/file-upload/actions/upload-image.js +5 -0
  74. package/dist/framework-tools.js +2 -0
  75. package/dist/history/actions/create-resource-version.js +5 -0
  76. package/dist/history/actions/restore-resource-version.js +5 -0
  77. package/dist/ingestion/index.d.ts +1 -1
  78. package/dist/ingestion/index.js +1 -1
  79. package/dist/ingestion/pptx.d.ts +11 -0
  80. package/dist/ingestion/pptx.js +81 -1
  81. package/dist/integrations/actions/manage-messaging-channel.js +5 -0
  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/mcp/screen-memory-stdio.d.ts +7 -7
  86. package/dist/observability/actions/save-observability-instruction-update.js +5 -0
  87. package/dist/observability/actions/save-observability-review-summary.js +5 -0
  88. package/dist/provider-api/actions/custom-provider-registration.d.ts +19 -19
  89. package/dist/provider-api/actions/provider-api.d.ts +10 -10
  90. package/dist/provider-api/index.js +9 -2
  91. package/dist/review/actions/consume-review-feedback.js +5 -0
  92. package/dist/review/actions/create-review-comment.js +5 -0
  93. package/dist/review/actions/delete-review-comment.js +5 -0
  94. package/dist/review/actions/react-to-review-comment.js +5 -0
  95. package/dist/review/actions/reply-review-comment.js +5 -0
  96. package/dist/review/actions/resolve-review-thread.js +5 -0
  97. package/dist/review/actions/send-review-thread-to-agent.js +5 -0
  98. package/dist/review/actions/set-review-status.js +5 -0
  99. package/dist/review/actions/set-review-thread-muted.js +5 -0
  100. package/dist/review/actions/set-review-thread-unread.js +5 -0
  101. package/dist/review/actions/set-review-threads-unread.js +5 -0
  102. package/dist/review/actions/update-review-comment-anchor.js +5 -0
  103. package/dist/review/actions/update-review-comment.js +5 -0
  104. package/dist/review/suggestions/actions.js +60 -21
  105. package/dist/review/suggestions/store.d.ts +2 -0
  106. package/dist/review/suggestions/store.js +28 -0
  107. package/dist/secrets/actions/delete-api-key.js +5 -0
  108. package/dist/secrets/routes.d.ts +10 -10
  109. package/dist/server/action-discovery.js +8 -0
  110. package/dist/server/agent-chat/context-tools.js +105 -2
  111. package/dist/server/agent-chat-plugin.d.ts +2 -0
  112. package/dist/server/agent-chat-plugin.js +242 -54
  113. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  114. package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
  115. package/dist/server/application-state-maintenance.d.ts +2 -0
  116. package/dist/server/application-state-maintenance.js +2 -0
  117. package/dist/server/attribution.d.ts +14 -0
  118. package/dist/server/attribution.js +62 -2
  119. package/dist/server/auth.js +7 -0
  120. package/dist/server/consent-route.d.ts +41 -0
  121. package/dist/server/consent-route.js +102 -0
  122. package/dist/server/first-touch-route.d.ts +39 -0
  123. package/dist/server/first-touch-route.js +115 -0
  124. package/dist/server/index.d.ts +1 -0
  125. package/dist/server/index.js +1 -0
  126. package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
  127. package/dist/server/queued-submission-inbox-drain.js +12 -0
  128. package/dist/server/request-origin.d.ts +6 -0
  129. package/dist/server/request-origin.js +12 -0
  130. package/dist/settings/org-settings.d.ts +2 -1
  131. package/dist/settings/org-settings.js +4 -1
  132. package/dist/settings/store.d.ts +8 -0
  133. package/dist/settings/store.js +14 -5
  134. package/dist/shared/consent.d.ts +31 -0
  135. package/dist/shared/consent.js +145 -0
  136. package/dist/shared/first-touch-persistence.d.ts +31 -0
  137. package/dist/shared/first-touch-persistence.js +53 -0
  138. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  139. package/dist/sharing/actions/set-resource-visibility.js +5 -0
  140. package/dist/sharing/actions/share-resource.js +5 -0
  141. package/dist/sharing/actions/unshare-resource.js +5 -0
  142. package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  143. package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  144. package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  145. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  146. package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  147. package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  148. package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  149. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
  150. package/dist/usage/actions/get-usage-metrics.js +27 -4
  151. package/dist/usage/actions/manage-usage-alert.js +5 -0
  152. package/dist/vite/client.js +8 -6
  153. package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
  154. package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
  155. package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
  156. package/docs/content/actions-access-control.mdx +8 -8
  157. package/docs/content/actions-defining.mdx +9 -8
  158. package/docs/content/template-design-developers.mdx +9 -9
  159. package/docs/content/template-design-features.mdx +1 -3
  160. package/docs/content/turn-into-app.mdx +4 -0
  161. package/package.json +4 -3
  162. package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
  163. package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
  164. package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
  165. package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
  166. package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
  167. package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
  168. package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
  169. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
@@ -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
@@ -329,10 +329,26 @@ chase arrivals or expand a finite catch-up request into an all-history audit.
329
329
  administrative post or duplicate; record the reason and link a duplicate to
330
330
  its canonical report. Include
331
331
  the root `threadParentTs`, reply timestamp, author ID, matching disposition,
332
- evidence, and read-back text. For each human/team handoff, the visible status
333
- reply must name its distinct scope, owner state, and action. Every distinct
334
- unfinished team action gets this actor's root `🎫`, even when no person has
335
- accepted it. For `status: "unassigned"`, record the responsible team/role or
332
+ evidence, and read-back text. Keep exact scope, proof, and handoff details in
333
+ the ledger. For `Owned elsewhere`, keep the owner's full proof in
334
+ `otherOwnerEvidence.statusReply.evidence`; set its `publicEvidenceSummary` to
335
+ a brief plain-language phrase (2–12 words) that appears in both the evidence
336
+ and the owner's captured reply. Do not require the full internal evidence in
337
+ their Slack text. For active `🎫` actions, add a short plain-language
338
+ `pendingActionSummary` to `statusReply` that names every open action and its
339
+ known owner, and include it in the reply; omit it when no tracked action
340
+ remains open. Keep the exact action in the internal ledger. When that wording
341
+ is too technical or long for Slack, add a
342
+ concise plain-language `publicActionSummary` using the opening words of the
343
+ action and leaving trailing implementation detail out. It must have at least
344
+ two meaningful words and no more than 12 words; the checker requires the
345
+ phrase to match the action. Use the summary in public status replies and
346
+ other readbacks that do not prove owner acceptance. For an accepted handoff,
347
+ the owner's explicit acceptance and the direct request before contextual
348
+ assent must name the full recorded action, even when a shorter public
349
+ summary exists. Every
350
+ distinct unfinished team action gets this actor's root `🎫`, even when no
351
+ person has accepted it. For `status: "unassigned"`, record the responsible team/role or
336
352
  `unassigned`; omit the owner Slack ID and acceptance. If this actor asked a
337
353
  named person to take the action but they have not accepted, record the exact
338
354
  request and keep the handoff unassigned. For `status: "accepted"` or
@@ -363,7 +379,19 @@ chase arrivals or expand a finite catch-up request into an all-history audit.
363
379
  replies and bot messages. The status reply must be newer than this human
364
380
  reply. If a human answers later, update the disposition and status before
365
381
  reconciling it.
366
- Record each verified `fixedScopes` entry with its proof; record each
382
+ Record each verified `fixedScopes` entry with its proof. For a status with
383
+ fixed scopes, also set `statusReply.publicEvidenceSummary` to a brief,
384
+ plain-language phrase (2–12 words) that can appear in the public reply. For
385
+ every fixed scope, put that scope and the summary together in one sentence of
386
+ its `verification`. Include the summary in both `statusReply.evidence` and
387
+ the captured `statusReply.text`; keep detailed proof in the ledger. The
388
+ summary may paraphrase the internal scope. Record each
389
+ `unfinishedScopes` entry in the ledger. When any remain, set
390
+ `statusReply.unfinishedScopeSummary` to a brief plain-language summary
391
+ (3–12 words) that names remaining work using wording grounded in its recorded
392
+ scope or evidence, and says it is still open; include it in the public status
393
+ even when no separate `🎫` action exists. Omit this field when no unfinished
394
+ scope remains. Record each
367
395
  unfinished team/engineering action in `handoffs[]` and each outstanding
368
396
  reporter input request in `reporterRequests[]` with its scope, exact action,
369
397
  and exact `requestReply`. For
@@ -386,9 +414,9 @@ chase arrivals or expand a finite catch-up request into an all-history audit.
386
414
  action is completed, keep it in `handoffs[]` with
387
415
  `status: "completed"` and `completion: { evidence, sourceUrl }` or an exact
388
416
  owner `reply` (`ts`, `threadParentTs`, `actorId`, and verbatim `text`). The
389
- current status must cite that completion evidence. Keep the root `🎫` as
390
- history; completed actions are not open follow-ups and do not block a closed
391
- disposition. Only an owner withdrawal moves an accepted action to
417
+ `statusReply.evidence` must cite that completion evidence. Keep the root
418
+ `🎫` as history; completed actions are not open follow-ups and do not block a
419
+ closed disposition. Only an owner withdrawal moves an accepted action to
392
420
  `historicalReactionMarks[]`. As soon as direct post-change proof passes, add this actor's
393
421
  `✅` to the root and read it back before moving to another scope or report,
394
422
  including while its PR is open. Before merge, record **Verified locally** and
@@ -403,9 +431,10 @@ chase arrivals or expand a finite catch-up request into an all-history audit.
403
431
  mark remains as history after completion. For an eligible open scope this
404
432
  workflow takes, retain the root `👀` as permanent history; do not use it to
405
433
  infer whether work remains.
406
- The same-thread status reply must name the verified scope(s), the remaining
407
- open scope(s), each open scope's blocker and next action, and why `✅` or `🎫`
408
- is absent when it does not apply. A reply does not replace a
434
+ Keep the same-thread status reply to one short, plain-language paragraph.
435
+ Say what changed; when an active `🎫` remains, name its next action through
436
+ `pendingActionSummary`. Do not list every scope or explain absent reactions.
437
+ A reply does not replace a
409
438
  reaction, and a reaction does not replace a reply. Do not add status
410
439
  requirements or reactions to another actor's eye. When later evidence
411
440
  invalidates a retained `✅`, remove that scope from active `fixedScopes[]`
@@ -415,9 +444,17 @@ chase arrivals or expand a finite catch-up request into an all-history audit.
415
444
  withdraws, move that action out of current `handoffs[]` and record a historical
416
445
  `🎫` with its earlier accepted `handoff` plus the owner's exact
417
446
  `withdrawalReply` (`ts`, `threadParentTs`, `actorId`, and verbatim `text`).
418
- Explain each retained mark in the current status and its reaction decision;
419
- preserve it without presenting it as current proof or an active handoff. The
420
- checker validates historical evidence against the captured thread. When every report scope
447
+ Record why each retained mark is historical in the internal reaction
448
+ decision; preserve it without presenting it as current proof or an active
449
+ handoff. Keep detailed proof in `previousStatus.evidence` in the internal
450
+ ledger. For a historical `✅`, also record a brief, non-sensitive
451
+ `publicEvidenceSummary` (2–12 words) drawn from that proof. It may paraphrase
452
+ the exact scope, but the scope and summary must appear together in one proof
453
+ sentence. Include the summary in the captured `previousStatus.text`; the
454
+ checker verifies that it is tied to proof for the recorded scope.
455
+ Never put secrets, customer details, or raw logs in the summary. For a
456
+ historical `🎫`, the prior reply must name both the accepted action and its
457
+ owner. The checker validates these details against the captured thread. When every report scope
421
458
  and follow-up is closed, post or reuse the final same-thread status and read
422
459
  back the status and reactions. Preserve every reaction; disposition and
423
460
  status show that work is closed even when the root still has `👀`.
@@ -481,8 +518,9 @@ back `🎫` even when it is unassigned or unaccepted. Record acceptance only
481
518
  after a named person's exact reply; otherwise state `owner: unassigned` and
482
519
  `status: unassigned`. For reporter evidence, access, or clarification
483
520
  requests, record `reporterRequests[]` and add/read back `🎫`; explain that it
484
- tracks requested input, not a team handoff. In the current status, state the
485
- exact proof gap, blocker, and next owner/action. An
521
+ tracks requested input, not a team handoff. In the internal ledger, record the
522
+ exact proof gap, blocker, and next owner/action. Keep the current status brief
523
+ and plain-language. An
486
524
  eye-only root with unfinished work is pending; an eye-only root with a closed
487
525
  verified disposition may retain the eye as history. Never remove or clean up a
488
526
  reaction. Slack thread replies appear under the root's reply count, not as
@@ -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