@vellumai/assistant 0.4.3 → 0.4.4

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 (183) hide show
  1. package/.env.example +3 -0
  2. package/ARCHITECTURE.md +40 -3
  3. package/README.md +43 -35
  4. package/package.json +1 -1
  5. package/scripts/ipc/generate-swift.ts +1 -0
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +58 -120
  7. package/src/__tests__/actor-token-service.test.ts +1099 -0
  8. package/src/__tests__/agent-loop.test.ts +51 -0
  9. package/src/__tests__/approval-routes-http.test.ts +2 -0
  10. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -5
  11. package/src/__tests__/assistant-id-boundary-guard.test.ts +125 -0
  12. package/src/__tests__/call-controller.test.ts +49 -0
  13. package/src/__tests__/call-pointer-message-composer.test.ts +171 -0
  14. package/src/__tests__/call-pointer-messages.test.ts +93 -3
  15. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +42 -0
  16. package/src/__tests__/callback-handoff-copy.test.ts +186 -0
  17. package/src/__tests__/channel-approval-routes.test.ts +133 -12
  18. package/src/__tests__/channel-guardian.test.ts +0 -87
  19. package/src/__tests__/channel-readiness-service.test.ts +10 -16
  20. package/src/__tests__/checker.test.ts +33 -12
  21. package/src/__tests__/config-schema.test.ts +4 -0
  22. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +410 -0
  23. package/src/__tests__/conversation-routes-guardian-reply.test.ts +256 -0
  24. package/src/__tests__/conversation-routes.test.ts +12 -3
  25. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  26. package/src/__tests__/daemon-server-session-init.test.ts +4 -0
  27. package/src/__tests__/guardian-actions-endpoint.test.ts +19 -14
  28. package/src/__tests__/guardian-dispatch.test.ts +8 -0
  29. package/src/__tests__/guardian-outbound-http.test.ts +4 -4
  30. package/src/__tests__/guardian-question-mode.test.ts +200 -0
  31. package/src/__tests__/guardian-routing-invariants.test.ts +178 -0
  32. package/src/__tests__/guardian-routing-state.test.ts +525 -0
  33. package/src/__tests__/handle-user-message-secret-resume.test.ts +2 -0
  34. package/src/__tests__/handlers-telegram-config.test.ts +0 -83
  35. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +55 -0
  36. package/src/__tests__/headless-browser-navigate.test.ts +2 -0
  37. package/src/__tests__/ipc-snapshot.test.ts +18 -51
  38. package/src/__tests__/non-member-access-request.test.ts +131 -8
  39. package/src/__tests__/notification-decision-fallback.test.ts +129 -4
  40. package/src/__tests__/notification-decision-strategy.test.ts +62 -2
  41. package/src/__tests__/notification-guardian-path.test.ts +3 -0
  42. package/src/__tests__/recording-intent-handler.test.ts +1 -0
  43. package/src/__tests__/relay-server.test.ts +841 -39
  44. package/src/__tests__/send-endpoint-busy.test.ts +5 -0
  45. package/src/__tests__/session-agent-loop.test.ts +1 -0
  46. package/src/__tests__/session-confirmation-signals.test.ts +523 -0
  47. package/src/__tests__/session-init.benchmark.test.ts +0 -1
  48. package/src/__tests__/session-surfaces-task-progress.test.ts +1 -1
  49. package/src/__tests__/session-tool-setup-app-refresh.test.ts +81 -2
  50. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
  51. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
  52. package/src/__tests__/tool-executor.test.ts +21 -2
  53. package/src/__tests__/tool-grant-request-escalation.test.ts +333 -27
  54. package/src/__tests__/trusted-contact-approval-notifier.test.ts +678 -0
  55. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1064 -0
  56. package/src/__tests__/twilio-config.test.ts +2 -13
  57. package/src/agent/loop.ts +1 -1
  58. package/src/approvals/guardian-decision-primitive.ts +10 -2
  59. package/src/approvals/guardian-request-resolvers.ts +128 -9
  60. package/src/calls/call-constants.ts +21 -0
  61. package/src/calls/call-controller.ts +9 -2
  62. package/src/calls/call-domain.ts +28 -7
  63. package/src/calls/call-pointer-message-composer.ts +154 -0
  64. package/src/calls/call-pointer-messages.ts +106 -27
  65. package/src/calls/guardian-dispatch.ts +4 -2
  66. package/src/calls/relay-server.ts +424 -12
  67. package/src/calls/twilio-config.ts +4 -11
  68. package/src/calls/twilio-routes.ts +1 -1
  69. package/src/calls/types.ts +3 -1
  70. package/src/cli.ts +5 -4
  71. package/src/config/bundled-skills/agentmail/SKILL.md +4 -0
  72. package/src/config/bundled-skills/app-builder/SKILL.md +146 -10
  73. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -1
  74. package/src/config/bundled-skills/email-setup/SKILL.md +1 -1
  75. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +105 -81
  76. package/src/config/bundled-skills/messaging/SKILL.md +61 -12
  77. package/src/config/bundled-skills/messaging/TOOLS.json +58 -0
  78. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +6 -1
  79. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +35 -0
  80. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +52 -0
  81. package/src/config/bundled-skills/phone-calls/SKILL.md +30 -39
  82. package/src/config/bundled-skills/twitter/SKILL.md +3 -3
  83. package/src/config/bundled-skills/vercel-token-setup/SKILL.md +1 -0
  84. package/src/config/calls-schema.ts +24 -0
  85. package/src/config/env.ts +22 -0
  86. package/src/config/feature-flag-registry.json +8 -0
  87. package/src/config/schema.ts +2 -2
  88. package/src/config/skills.ts +11 -0
  89. package/src/config/system-prompt.ts +11 -1
  90. package/src/config/templates/SOUL.md +2 -0
  91. package/src/config/vellum-skills/sms-setup/SKILL.md +71 -82
  92. package/src/config/vellum-skills/trusted-contacts/SKILL.md +10 -9
  93. package/src/config/vellum-skills/twilio-setup/SKILL.md +88 -73
  94. package/src/daemon/call-pointer-generators.ts +59 -0
  95. package/src/daemon/computer-use-session.ts +2 -5
  96. package/src/daemon/handlers/apps.ts +76 -20
  97. package/src/daemon/handlers/config-channels.ts +5 -55
  98. package/src/daemon/handlers/config-inbox.ts +9 -3
  99. package/src/daemon/handlers/config-ingress.ts +28 -3
  100. package/src/daemon/handlers/config-telegram.ts +12 -0
  101. package/src/daemon/handlers/config.ts +2 -6
  102. package/src/daemon/handlers/pairing.ts +2 -0
  103. package/src/daemon/handlers/sessions.ts +48 -3
  104. package/src/daemon/handlers/shared.ts +17 -2
  105. package/src/daemon/ipc-contract/integrations.ts +1 -99
  106. package/src/daemon/ipc-contract/messages.ts +47 -1
  107. package/src/daemon/ipc-contract/notifications.ts +11 -0
  108. package/src/daemon/ipc-contract-inventory.json +2 -4
  109. package/src/daemon/lifecycle.ts +17 -0
  110. package/src/daemon/server.ts +14 -1
  111. package/src/daemon/session-agent-loop-handlers.ts +20 -0
  112. package/src/daemon/session-agent-loop.ts +22 -11
  113. package/src/daemon/session-lifecycle.ts +1 -1
  114. package/src/daemon/session-process.ts +11 -1
  115. package/src/daemon/session-runtime-assembly.ts +3 -0
  116. package/src/daemon/session-surfaces.ts +3 -2
  117. package/src/daemon/session.ts +88 -1
  118. package/src/daemon/tool-side-effects.ts +22 -0
  119. package/src/home-base/prebuilt/brain-graph.html +1483 -0
  120. package/src/home-base/prebuilt/index.html +40 -0
  121. package/src/inbound/platform-callback-registration.ts +157 -0
  122. package/src/memory/canonical-guardian-store.ts +1 -1
  123. package/src/memory/db-init.ts +4 -0
  124. package/src/memory/migrations/038-actor-token-records.ts +39 -0
  125. package/src/memory/migrations/index.ts +1 -0
  126. package/src/memory/schema.ts +16 -0
  127. package/src/messaging/provider-types.ts +24 -0
  128. package/src/messaging/provider.ts +7 -0
  129. package/src/messaging/providers/gmail/adapter.ts +127 -0
  130. package/src/messaging/providers/sms/adapter.ts +40 -37
  131. package/src/notifications/adapters/macos.ts +45 -2
  132. package/src/notifications/broadcaster.ts +16 -0
  133. package/src/notifications/copy-composer.ts +39 -1
  134. package/src/notifications/decision-engine.ts +22 -9
  135. package/src/notifications/destination-resolver.ts +16 -2
  136. package/src/notifications/emit-signal.ts +16 -8
  137. package/src/notifications/guardian-question-mode.ts +419 -0
  138. package/src/notifications/signal.ts +14 -3
  139. package/src/permissions/checker.ts +13 -1
  140. package/src/permissions/prompter.ts +14 -0
  141. package/src/providers/anthropic/client.ts +20 -0
  142. package/src/providers/provider-send-message.ts +15 -3
  143. package/src/runtime/access-request-helper.ts +71 -1
  144. package/src/runtime/actor-token-service.ts +234 -0
  145. package/src/runtime/actor-token-store.ts +236 -0
  146. package/src/runtime/channel-approvals.ts +5 -3
  147. package/src/runtime/channel-readiness-service.ts +23 -64
  148. package/src/runtime/channel-readiness-types.ts +3 -4
  149. package/src/runtime/channel-retry-sweep.ts +4 -1
  150. package/src/runtime/confirmation-request-guardian-bridge.ts +197 -0
  151. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  152. package/src/runtime/guardian-context-resolver.ts +82 -0
  153. package/src/runtime/guardian-outbound-actions.ts +0 -3
  154. package/src/runtime/guardian-reply-router.ts +67 -30
  155. package/src/runtime/guardian-vellum-migration.ts +57 -0
  156. package/src/runtime/http-server.ts +65 -12
  157. package/src/runtime/http-types.ts +13 -0
  158. package/src/runtime/invite-redemption-service.ts +8 -0
  159. package/src/runtime/local-actor-identity.ts +76 -0
  160. package/src/runtime/middleware/actor-token.ts +271 -0
  161. package/src/runtime/routes/approval-routes.ts +82 -7
  162. package/src/runtime/routes/brain-graph-routes.ts +222 -0
  163. package/src/runtime/routes/channel-readiness-routes.ts +71 -0
  164. package/src/runtime/routes/conversation-routes.ts +140 -52
  165. package/src/runtime/routes/events-routes.ts +20 -5
  166. package/src/runtime/routes/guardian-action-routes.ts +45 -3
  167. package/src/runtime/routes/guardian-approval-interception.ts +29 -0
  168. package/src/runtime/routes/guardian-bootstrap-routes.ts +145 -0
  169. package/src/runtime/routes/inbound-message-handler.ts +143 -2
  170. package/src/runtime/routes/integration-routes.ts +7 -15
  171. package/src/runtime/routes/pairing-routes.ts +163 -0
  172. package/src/runtime/routes/twilio-routes.ts +934 -0
  173. package/src/runtime/tool-grant-request-helper.ts +3 -1
  174. package/src/security/oauth2.ts +27 -2
  175. package/src/security/token-manager.ts +46 -10
  176. package/src/tools/browser/browser-execution.ts +4 -3
  177. package/src/tools/browser/browser-handoff.ts +10 -18
  178. package/src/tools/browser/browser-manager.ts +80 -25
  179. package/src/tools/browser/browser-screencast.ts +35 -119
  180. package/src/tools/permission-checker.ts +15 -4
  181. package/src/tools/tool-approval-handler.ts +242 -18
  182. package/src/__tests__/handlers-twilio-config.test.ts +0 -1928
  183. package/src/daemon/handlers/config-twilio.ts +0 -1082
@@ -34,6 +34,7 @@ These are hard prohibitions. Violating any of these produces that unmistakable "
34
34
  - **NEVER** make all text the same size and weight — establish clear hierarchy with at least 3 distinct levels
35
35
  - **NEVER** use a pure white (`#fff`) or pure dark (`#000`/`#0a0a0a`) background — ALWAYS tint it to match the domain (cream `#FEFCF9` for lifestyle, sage `#F0F5F0` for nature, cool gray `#F5F7FA` for finance, warm blush `#FDF6F3` for wellness)
36
36
  - **NEVER** leave clickable elements without hover AND active states
37
+ - **NEVER** hand-code SVG/CSS charts (lines, bars, sparklines, gauges) — ALWAYS use `vellum.widgets.lineChart()`, `.barChart()`, `.sparkline()`, or `.progressRing()`. They handle bounds, clipping, scaling, and dark mode correctly. Hand-coded charts invariably overflow and bleed into adjacent elements.
37
38
  - **ALWAYS** use emoji as visual identifiers in stat cards, list items, and navigation — they replace icon libraries and add instant personality (🍎 for food, 🔥 for streaks, 💰 for money, 🌿 for plants)
38
39
  - **ALWAYS** apply the accent-word pattern in hero headings — color ONE key word or phrase in the accent color: "Your <span style='color: var(--accent)'>Week</span> in Motion"
39
40
  - **ALWAYS** include a contextual/personalized header — a greeting ("Good morning"), date ("Saturday, Feb 15"), or welcome ("Welcome back, Alex") — not just the app title
@@ -92,6 +93,23 @@ These are hard prohibitions. Violating any of these produces that unmistakable "
92
93
  Copy-paste-ready CSS techniques. All work in the sandboxed WebView with no external dependencies.
93
94
 
94
95
  ### Animated Gradient Background
96
+
97
+ Choose **one** of the following color variants (do not combine both):
98
+
99
+ **Variant A — Warm pastels (light, airy feel):**
100
+ ```css
101
+ body {
102
+ background: linear-gradient(-45deg, #fef3c7, #fce7f3, #e0e7ff, #d1fae5);
103
+ background-size: 400% 400%;
104
+ animation: gradientShift 15s ease infinite;
105
+ }
106
+ @keyframes gradientShift {
107
+ 0%, 100% { background-position: 0% 50%; }
108
+ 50% { background-position: 100% 50%; }
109
+ }
110
+ ```
111
+
112
+ **Variant B — Dark jewel tones (deep, rich feel):**
95
113
  ```css
96
114
  body {
97
115
  background: linear-gradient(-45deg, #0f172a, #1e1b4b, #172554, #0c4a6e);
@@ -108,9 +126,9 @@ body {
108
126
  ```css
109
127
  body {
110
128
  background:
111
- radial-gradient(ellipse at 20% 50%, color-mix(in srgb, var(--v-violet-500) 15%, transparent) 0%, transparent 50%),
112
- radial-gradient(ellipse at 80% 20%, color-mix(in srgb, var(--v-indigo-500) 12%, transparent) 0%, transparent 50%),
113
- radial-gradient(ellipse at 50% 80%, color-mix(in srgb, var(--v-emerald-500) 8%, transparent) 0%, transparent 50%),
129
+ radial-gradient(ellipse at 20% 50%, color-mix(in srgb, var(--v-rose-400) 15%, transparent) 0%, transparent 50%),
130
+ radial-gradient(ellipse at 80% 20%, color-mix(in srgb, var(--v-amber-400) 12%, transparent) 0%, transparent 50%),
131
+ radial-gradient(ellipse at 50% 80%, color-mix(in srgb, var(--v-teal-400) 10%, transparent) 0%, transparent 50%),
114
132
  var(--v-bg);
115
133
  }
116
134
  ```
@@ -161,7 +179,7 @@ body::before {
161
179
  ### Gradient Text
162
180
  ```css
163
181
  .gradient-text {
164
- background: linear-gradient(135deg, var(--v-violet-500), var(--v-indigo-400));
182
+ background: linear-gradient(135deg, var(--v-rose-500), var(--v-amber-400));
165
183
  -webkit-background-clip: text;
166
184
  -webkit-text-fill-color: transparent;
167
185
  background-clip: text;
@@ -348,7 +366,7 @@ document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
348
366
  .accent-word { color: var(--accent, var(--v-accent)); }
349
367
  /* Gradient variant — use .v-gradient-text from the design system, or customize: */
350
368
  .accent-gradient {
351
- background: linear-gradient(135deg, var(--accent, var(--v-violet-500)), var(--v-indigo-400));
369
+ background: linear-gradient(135deg, var(--accent, var(--v-rose-500)), var(--v-amber-400));
352
370
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
353
371
  }
354
372
  ```
@@ -1021,7 +1039,9 @@ async function handleBulk(action) {
1021
1039
  }
1022
1040
  ```
1023
1041
 
1024
- **Presentation slideshow** — multi-slide deck with 8 layout variants (title, stats, bullets, quote, comparison, visual, timeline, closing). Use the slideshow widget for presentations, pitch decks, and multi-slide educational content. The model provides slide content; the widget handles navigation, transitions, and keyboard support.
1042
+ **Presentation slideshow** — multi-slide deck with 8 layout variants (title, stats, bullets, quote, comparison, visual, timeline, closing). Use the slideshow widget for presentations, pitch decks, and multi-slide educational content. The model provides slide content; the widget handles navigation, transitions, and keyboard support. Never tell the user how to navigate slides — the UI is self-explanatory.
1043
+
1044
+ > **For comprehensive slide design guidelines, see the "Presentation Slide Design" section below.** The following HTML shows the structural template for all 8 layout types.
1025
1045
 
1026
1046
  ```html
1027
1047
  <!DOCTYPE html>
@@ -1159,7 +1179,7 @@ document.addEventListener('DOMContentLoaded', function() {
1159
1179
  - **Use widgets** for standard patterns — tables, metrics, timelines, notifications, presentations
1160
1180
  - **Use custom HTML** for novel or creative UIs — games, art tools, unique dashboards
1161
1181
  - **Mix freely** — widgets compose well together and with custom elements
1162
- - Always prioritize the ideal user experience over using the widget library
1182
+ - Always prioritize the ideal user experience over using the widget library — EXCEPT for charts: always use `vellum.widgets.*` chart functions (lineChart, barChart, sparkline, progressRing) instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
1163
1183
 
1164
1184
  #### Advanced techniques
1165
1185
 
@@ -1332,7 +1352,25 @@ Both `ui_show` and `app_create` support a `preview` object for an inline chat pr
1332
1352
  }
1333
1353
  ```
1334
1354
 
1335
- **With `app_create`:**
1355
+ **With `app_create` (image URL icon):**
1356
+ ```json
1357
+ {
1358
+ "name": "Microsoft Overview",
1359
+ "schema_json": "{}",
1360
+ "html": "...",
1361
+ "preview": {
1362
+ "title": "Microsoft",
1363
+ "subtitle": "3 Slides",
1364
+ "icon": "https://www.microsoft.com/favicon.ico",
1365
+ "metrics": [
1366
+ { "label": "Founded", "value": "1975" },
1367
+ { "label": "Market Cap", "value": "$2.98T" }
1368
+ ]
1369
+ }
1370
+ }
1371
+ ```
1372
+
1373
+ **With `app_create` (emoji icon):**
1336
1374
  ```json
1337
1375
  {
1338
1376
  "name": "Expense Tracker",
@@ -1349,7 +1387,7 @@ Both `ui_show` and `app_create` support a `preview` object for an inline chat pr
1349
1387
  }
1350
1388
  ```
1351
1389
 
1352
- Preview fields: `title` (required), `subtitle`, `description`, `icon` (emoji), `metrics` (up to 3 key-value pills). When `app_create` is called with `auto_open: true` (the default), the preview is forwarded through `app_open` automatically.
1390
+ Preview fields: `title` (required), `subtitle`, `description`, `icon`, `metrics` (up to 3 key-value pills). The `icon` field accepts an emoji or an image URL. **Prefer an image URL whenever you have a relevant one** — logos, favicons, product images, headshots, flags, album art, or any image you encountered during research. The preview card renders image URLs as a thumbnail automatically. Fall back to emoji only when there is no natural image. When `app_create` is called with `auto_open: true` (the default), the preview is forwarded through `app_open` automatically.
1353
1391
 
1354
1392
  ### 6. Handle Iteration
1355
1393
 
@@ -1490,7 +1528,105 @@ Before delivering any app, mentally verify these 10 items — they cover the gap
1490
1528
  | `.v-metric-card .v-metric-icon` | Emoji icon in metric cards | Place emoji `<span>` with `.v-metric-icon` inside `.v-metric-card` |
1491
1529
  | `.v-slideshow` | Presentation slide deck with transitions | `.v-slide` (`.active`), `.v-slide-label`, `.v-slide-title`, `.v-slide-body`, `.v-slide-stats`, `.v-slide-stat`, `.v-slide-quote` — init with `vellum.widgets.slideshow()` |
1492
1530
 
1493
- Every app should include: search/filter, toast notifications for all CRUD operations, `window.vellum.confirm()` for destructive actions, staggered page-load animation, card hover effects, and skeleton loading states.
1531
+ Every app should include: search/filter, toast notifications for all CRUD operations, `window.vellum.confirm()` for destructive actions, staggered page-load animation, card hover effects, and skeleton loading states. (These requirements do not apply to presentation slide decks — see "Presentation Slide Design" below.)
1532
+
1533
+ ## Presentation Slide Design
1534
+
1535
+ ### Slide Design Philosophy
1536
+
1537
+ - **One idea per slide** — each slide communicates a single concept, not a cluster of related points
1538
+ - **Glanceable, not readable** — a slide should be understood in 3 seconds; dense text belongs in documents, not presentations
1539
+ - **Visual storytelling arc** — open strong, build context, create emotional resonance, close with impact
1540
+ - **Cinematic quality bar** — every deck should feel at home in a startup pitch, TED talk, or Apple keynote
1541
+ - **The slide is the visual** — don't describe what the audience should imagine; show it through layout, color, and typography
1542
+
1543
+ ### What App Rules to Skip for Slides
1544
+
1545
+ The general app design checklist does NOT apply to slide decks. Specifically skip:
1546
+
1547
+ - Contextual header/greeting ("Good morning, Alex") — slides are not dashboards
1548
+ - Search/filter, pill toggles, suggestion chips — slides are not interactive apps
1549
+ - Toast notifications, confirm dialogs, form validation — no CRUD in slides
1550
+ - Data bridge API / `window.vellum.data` — slides are static content
1551
+ - Skeleton loading states — slides render instantly
1552
+ - Mandatory trust/status pill badge — use only when slide content calls for it (e.g., a "verified" badge on a stats slide)
1553
+ - Mandatory emoji stat cards — use when they strengthen the message, skip when they clutter
1554
+ - The app Pre-Ship Design Checklist — use the Slide Pre-Ship Checklist instead
1555
+
1556
+ ### Slide Typography
1557
+
1558
+ - **Title slides:** `clamp(2rem, 5vw, 3rem)`, weight 800 — much larger than app text
1559
+ - **Body text:** `clamp(1rem, 2.5vw, 1.25rem)` — larger than app body (14px); keep to 2–3 sentences max
1560
+ - **Stat values:** `clamp(1.75rem, 4vw, 2.5rem)` — big numbers are the most impactful element on any slide
1561
+ - **Accent-word technique is ESSENTIAL** — even more than apps, every heading should color one key word with the accent color
1562
+ - **Contrast is everything** — near-white on dark, near-black on light; no washed-out middle ground
1563
+ - **Never go below 15px** for any visible text — if it doesn't fit, cut words, don't shrink font
1564
+
1565
+ ### Slide Color & Visual Treatment
1566
+
1567
+ - **Bold, full-bleed backgrounds** — warm cream, blush pink, soft lavender, deep navy, rich purple, dark emerald; vary light and dark across the deck
1568
+ - **Animated gradient backgrounds** are ideal for title and closing slides — use `background-size: 400% 400%` with CSS animation
1569
+ - **Domain-matched palettes still apply**, just executed more dramatically — a finance deck is navy/gold, a health deck is teal/white
1570
+ - **One accent color used sparingly** — titles, stat borders, label dots, CTA buttons; never more than one accent
1571
+ - **Glassmorphism works well** for slide overlays on visual/immersive slides — `backdrop-filter: blur()` with semi-transparent bg
1572
+ - **Full-screen immersion:** `.v-slideshow` should use `border-radius: 0; min-height: 100vh` for edge-to-edge feel
1573
+ - **Vary background darkness across slides** — alternate between dark, medium, and light backgrounds to create visual rhythm
1574
+
1575
+ ### Slide Layout Rhythm
1576
+
1577
+ When to use each of the 8 layout variants:
1578
+
1579
+ | Type | When to Use |
1580
+ |---|---|
1581
+ | **Title** | Bold title with accent word, subtitle, optional badge — always first |
1582
+ | **Stats** | Early for credibility; 2–4 stat cards with big numbers |
1583
+ | **Bullets / Content** | Core message; 3–5 bullets max, or 2–3 sentence body |
1584
+ | **Quote** | Emotional punctuation; center-aligned, breaks visual pattern |
1585
+ | **Comparison** | Two-column before/after, entity comparison, or pros/cons |
1586
+ | **Timeline** | Chronological progression; milestones, history, roadmap, or process steps using `.v-timeline-entry` entries |
1587
+ | **Visual / Immersive** | Gradient background with glass overlay, minimal text |
1588
+ | **Closing / CTA** | Bold title, short takeaway, optional stat reinforcement |
1589
+
1590
+ **Layout rhythm rules:**
1591
+
1592
+ - **NEVER** two slides of the same type back-to-back
1593
+ - **5–8 slides:** title → stats → bullets → quote → comparison or timeline or visual → closing
1594
+ - **3–4 slides:** title → stats or bullets → closing
1595
+ - **10+ slides:** repeat content/stats but always separate with a quote, timeline, or visual slide
1596
+ - **Every deck needs at least 3 different layout types** — variety creates visual interest
1597
+
1598
+ ### Slide Anti-Slop Rules
1599
+
1600
+ - **NEVER** more than 6 bullet points per slide — if you have more, split into two slides
1601
+ - **NEVER** body text smaller than 15px — cut words instead of shrinking
1602
+ - **NEVER** the same background color on consecutive slides — vary dark/light/gradient
1603
+ - **NEVER** skip accent-word on title/heading slides — it's the #1 visual technique
1604
+ - **NEVER** use `.v-slide-label` on every single slide — aim for 40–60% of slides
1605
+ - **NEVER** center-align bullet slides — only center quotes and closing slides
1606
+ - **NEVER** use the same stat value format everywhere — mix `$2.4M`, `147%`, `3x`, `12k+` for variety
1607
+ - **NEVER** hand-code charts on slides — use `vellum.widgets.lineChart()` / `.barChart()` / `.sparkline()` / `.progressRing()` rendered into a `<div>` with a fixed height. Hand-coded chart SVGs bleed into adjacent slide elements.
1608
+
1609
+ ### Slide Pre-Ship Checklist
1610
+
1611
+ Before delivering any slide deck, verify:
1612
+
1613
+ 1. **Domain-matched palette** — colors match the topic (not default violet for everything)
1614
+ 2. **Bold background** — dark, gradient, or strongly tinted; not plain white
1615
+ 3. **Accent word in every title** — one key word colored with the accent
1616
+ 4. **One idea per slide** — each slide understood in 3 seconds
1617
+ 5. **Layout variety** — 3+ different layout types, no consecutive same-type
1618
+ 6. **Typography scale** — clear hierarchy; titles much larger than body text
1619
+ 7. **Sparse content** — max 6 bullets, max 3 sentences body text per slide
1620
+ 8. **Visual punctuation** — at least one quote, visual, or center-aligned slide
1621
+ 9. **Strong open and close** — impactful title slide, clear takeaway closing
1622
+ 10. **Immersive feel** — full-viewport slides, `min-height: 100vh; border-radius: 0`
1623
+
1624
+ ### What Great Slide Decks Look Like
1625
+
1626
+ - **Startup pitch deck** — dark navy animated gradient, accent-word title, trust pill on stats, big stat numbers (`$12M ARR`, `3x growth`), customer quote mid-deck, CTA closing with one bold ask
1627
+ - **Company overview** — corporate blue on charcoal, stats-heavy early slides, comparison slide (us vs. competitors), timeline slide, professional/minimal emoji usage
1628
+ - **Educational deck** — bright accent on light background, emoji in bullet points for visual anchoring, expert quote, glass overlay visual slide, "key takeaways" closing
1629
+ - **Creative agency deck** — bold saturated palette, animated gradient backgrounds, minimal text per slide, maximum visual drama, notable client quote, portfolio-style comparison
1494
1630
 
1495
1631
  ## Error Handling
1496
1632
 
@@ -50,7 +50,7 @@
50
50
  "title": { "type": "string", "description": "Preview card title" },
51
51
  "subtitle": { "type": "string", "description": "Optional subtitle" },
52
52
  "description": { "type": "string", "description": "Optional short description" },
53
- "icon": { "type": "string", "description": "Optional emoji icon" },
53
+ "icon": { "type": "string", "description": "Optional icon — image URL preferred when available (logo, favicon, photo, etc.), emoji as fallback" },
54
54
  "metrics": {
55
55
  "type": "array",
56
56
  "description": "Optional key-value metrics",
@@ -9,7 +9,7 @@ You are setting up your own personal email address. This is a one-time operation
9
9
 
10
10
  ## Prerequisites
11
11
 
12
- Only proceed if the user explicitly asks you to create or set up your email address. Do NOT proactively run this skill.
12
+ Only proceed if the user explicitly asks you to create or set up **your own** (the assistant's) email address — e.g., "set up your email", "create your email address", "I want you to have your own email". Generic email requests like "send an email", "check my email", or "set up email" are about the **user's Gmail** and should be handled by the Messaging skill, not this one. Do NOT proactively run this skill.
13
13
 
14
14
  ## Step 1: Check if Email Already Exists
15
15
 
@@ -193,36 +193,36 @@ After the user authorizes (they'll come back and say so, or you can suggest they
193
193
 
194
194
  # Path B: Automated Setup (macOS Desktop App)
195
195
 
196
- You will automate the entire GCP setup via the browser while the user watches via screencast. The user's only manual actions are signing in to their Google account and one copy-paste for the client secret.
196
+ You will automate the entire GCP setup via the browser while the user watches in the Chrome window on the side. The user's only manual actions are: signing in to their Google account, and copy-pasting credentials from the Chrome window into secure prompts.
197
197
 
198
198
  ## Browser Interaction Principles
199
199
 
200
200
  Google Cloud Console's UI changes frequently. Do NOT memorize or depend on specific element IDs, CSS selectors, or DOM structures. Instead:
201
201
 
202
- 1. **Screenshot first, act second.** Before every interaction, take a `browser_screenshot` to see the current visual state. Use `browser_snapshot` to find interactive elements.
203
- 2. **Adapt to what you see.** If a button's label or position differs from what you expect, use the screenshot to find the correct element. GCP may rename buttons, reorganize menus, or change form layouts at any time.
204
- 3. **Verify after every action.** After clicking, typing, or navigating, take a new screenshot to confirm the action succeeded. If it didn't, try an alternative interaction (e.g., if a dropdown didn't open on click, try pressing Space or Enter).
205
- 4. **Never assume DOM structure.** Dropdowns may be `<select>`, `<mat-select>`, `<div role="listbox">`, or something else entirely. Use the snapshot to identify what's on the page and interact accordingly.
206
- 5. **When stuck, screenshot and describe.** If you cannot find an expected element after 2 attempts, take a screenshot, describe what you see to the user, and ask for guidance.
202
+ 1. **Snapshot first, act second.** Before every interaction, use `browser_snapshot` to discover interactive elements and their IDs. This is your primary navigation tool — it gives you the accessibility tree with clickable/typeable element IDs. Use `browser_screenshot` for visual context when the snapshot alone isn't enough.
203
+ 2. **Adapt to what you see.** If an element's label or position differs from what you expect, use the snapshot to find the correct element. GCP may rename buttons, reorganize menus, or change form layouts at any time.
204
+ 3. **Verify after every action.** After clicking, typing, or navigating, take a new snapshot to confirm the action succeeded. If it didn't, try an alternative interaction (e.g., if a dropdown didn't open on click, try pressing Space or Enter on the element).
205
+ 4. **Never assume DOM structure.** Dropdowns may be `<select>`, `<mat-select>`, `<div role="listbox">`, or something else entirely. Use the snapshot to identify element types and interact accordingly.
206
+ 5. **When stuck after 2 attempts, describe and ask.** Take a screenshot, describe what you see to the user, and ask for guidance.
207
207
 
208
208
  ## Anti-Loop Guardrails
209
209
 
210
210
  Each step has a **retry budget of 3 attempts**. An attempt is one try at the step's primary action (e.g., clicking a button, filling a form). If a step fails after 3 attempts:
211
211
 
212
212
  1. **Stop trying.** Do not continue retrying the same approach.
213
- 2. **Fall back to manual.** Tell the user what you were trying to do and ask them to complete that step manually in the browser. Give them the direct URL and clear text instructions.
213
+ 2. **Fall back to manual.** Tell the user what you were trying to do and ask them to complete that step manually in the Chrome window (which they can see on the side). Give them the direct URL and clear text instructions.
214
214
  3. **Resume automation** at the next step once the user confirms the manual step is done.
215
215
 
216
- If **two or more steps** require manual fallback, abandon the automated flow entirely and switch to giving the user the remaining steps as clear text instructions with links — using the correct OAuth type for the current flow (Desktop app for macOS, Web application for channels).
216
+ If **two or more steps** require manual fallback, abandon the automated flow entirely and switch to giving the user the remaining steps as clear text instructions with links — using "Desktop app" as the OAuth application type.
217
217
 
218
218
  ## Things That Do Not Work — Do Not Attempt
219
219
 
220
220
  These actions are technically impossible in the browser automation environment. Attempting them wastes time and leads to loops:
221
221
 
222
- - **Downloading files.** `browser_click` on a Download button does not save files to disk. The downloaded file will not appear anywhere accessible. There is NO JSON file to find at `~/Downloads` or anywhere else.
223
- - **Reading the Client Secret from a screenshot.** The Client Secret IS visible in the creation dialog, but you MUST NOT attempt to read it from a screenshot — it is too easy to misread characters, and the value must be exact. Always use the `credential_store prompt` approach to let the user copy-paste it accurately.
224
- - **Clipboard operations.** You cannot copy/paste via browser automation.
222
+ - **Downloading files.** `browser_click` on a Download button does not save files to disk. There is NO JSON file to find at `~/Downloads` or anywhere else. Never click Download buttons.
223
+ - **Clipboard operations.** You cannot copy/paste via browser automation. The user must manually copy values from the Chrome window.
225
224
  - **Deleting and recreating OAuth clients** to get a fresh secret — this orphans the stored client_id and causes `invalid_client` errors.
225
+ - **Navigating away from the credential dialog** before both credentials are stored — you will lose the Client Secret display and cannot get it back without creating a new client.
226
226
 
227
227
  ## Step 1: Single Upfront Confirmation
228
228
 
@@ -231,10 +231,11 @@ Use `ui_show` with `surface_type: "confirmation"` and this message:
231
231
  > **Set up Google Cloud for Gmail & Calendar**
232
232
  >
233
233
  > Here's what will happen:
234
- > 1. **A browser opens** — you sign in to your Google account
235
- > 2. **I automate everything** project creation, APIs, OAuth config, credentials
236
- > 3. **One quick copy-paste** — I'll create OAuth credentials and ask you to copy-paste the Client Secret from the dialog into a secure prompt
237
- > 4. **You authorize Vellum** with one click
234
+ > 1. **A browser opens on the side** — you'll be able to watch everything I do
235
+ > 2. **You sign in** to your Google account in the browser
236
+ > 3. **I automate everything** — project creation, APIs, OAuth config, credentials
237
+ > 4. **One copy-paste** I'll ask you to copy the Client Secret from the browser into a secure prompt
238
+ > 5. **You authorize Vellum** with one click
238
239
  >
239
240
  > The whole thing takes 2-3 minutes. Ready?
240
241
 
@@ -246,24 +247,32 @@ If the user declines, acknowledge and stop. No further confirmations are needed
246
247
 
247
248
  Navigate to `https://console.cloud.google.com/`.
248
249
 
249
- Take a screenshot and snapshot to check the page state:
250
- - **Sign-in page:** Tell the user: "Please sign in to your Google account in the browser preview panel (or the Chrome window that just opened)." Then auto-detect sign-in completion by polling screenshots every 5-10 seconds. Check if the current URL has moved away from `accounts.google.com` to `console.cloud.google.com`. Do NOT ask the user to "let me know when you're done" — detect it automatically. Once sign-in is detected, tell the user: "Signed in! Starting the automated setup now..."
250
+ Take a screenshot to check the page state:
251
+
252
+ - **Sign-in page:** Tell the user: "Please sign in to your Google account in the Chrome window on the right side of your screen." Then auto-detect sign-in completion by polling with `browser_screenshot` every 5-10 seconds — check if the URL has moved away from `accounts.google.com` to `console.cloud.google.com`. Do NOT ask the user to "let me know when you're done" — detect it automatically. Once sign-in is detected, tell the user: "Signed in! Starting the automated setup now..."
251
253
  - **Already signed in:** Tell the user: "Already signed in — starting setup now..." and continue immediately.
252
254
  - **CAPTCHA:** The browser automation's built-in handoff will handle this. If it persists, tell the user: "There's a CAPTCHA in the browser — please complete it and I'll continue automatically."
253
255
 
254
- **Verify:** URL contains `console.cloud.google.com` and no sign-in overlay is visible.
256
+ **What you should see when done:** URL contains `console.cloud.google.com` and no sign-in overlay is visible.
255
257
 
256
258
  ## Step 3: Create or Select a Project
257
259
 
258
260
  **Goal:** A GCP project named "Vellum Assistant" exists and is selected.
259
261
 
260
- Tell the user: "Creating Google Cloud project 'Vellum Assistant'..."
262
+ Tell the user: "Creating Google Cloud project..."
263
+
264
+ Navigate to `https://console.cloud.google.com/projectcreate`.
265
+
266
+ Take a `browser_snapshot`. Find the project name input field (look for an element with label containing "Project name" or a text input near the top of the form). Type "Vellum Assistant" into it.
261
267
 
262
- Navigate to `https://console.cloud.google.com/projectcreate`. Take a screenshot. Find the project name input field, enter "Vellum Assistant", and submit the form.
268
+ Look for a "Create" button in the snapshot and click it. Wait 10-15 seconds for project creation take a screenshot to check for:
269
+ - **Success message** or redirect to the new project dashboard — note the project ID from the URL or page content.
270
+ - **"Project name already in use" error** — that's fine. Navigate to `https://console.cloud.google.com/cloud-resource-manager` to find and select the existing "Vellum Assistant" project. Use `browser_extract` to read the project ID from the page.
271
+ - **Organization restriction or quota error** — tell the user what happened and ask them to resolve it.
263
272
 
264
- If the project already exists (e.g., an error says the name is taken or you see it in the project list), select the existing project instead. Note the project ID for subsequent steps.
273
+ **What you should see when done:** The project selector in the top bar shows the project name, and you have the project ID (something like `vellum-assistant-12345`).
265
274
 
266
- **Verify:** Take a screenshot. The console shows the project is active (project name visible in the header bar or a success message). Record the project ID.
275
+ Tell the user: "Project created!"
267
276
 
268
277
  ## Step 4: Enable Gmail and Calendar APIs
269
278
 
@@ -275,98 +284,111 @@ Navigate to each API's library page and enable it if not already enabled:
275
284
  1. `https://console.cloud.google.com/apis/library/gmail.googleapis.com?project=PROJECT_ID`
276
285
  2. `https://console.cloud.google.com/apis/library/calendar-json.googleapis.com?project=PROJECT_ID`
277
286
 
278
- For each page: take a screenshot. If the API shows as already enabled (e.g., "Manage" button or "API enabled" status), skip it. Otherwise, find and click the enable button, then wait for confirmation.
287
+ For each page: take a `browser_snapshot`. Look for:
288
+ - **"Enable" button** — click it, wait a few seconds, take another snapshot to confirm.
289
+ - **"Manage" button or "API enabled" text** — the API is already enabled. Skip it.
279
290
 
280
- **Verify:** Both API pages show an enabled/active state.
291
+ **What you should see when done:** Both API pages show "Manage" or "API enabled" status.
292
+
293
+ Tell the user: "APIs enabled!"
281
294
 
282
295
  ## Step 5: Configure OAuth Consent Screen
283
296
 
284
297
  **Goal:** An OAuth consent screen is configured with External user type, the required scopes, and the user added as a test user.
285
298
 
286
- Tell the user: "Configuring OAuth consent screen — this is the longest step, but it's fully automated..."
299
+ Tell the user: "Setting up OAuth consent screen — this is the longest step but it's fully automated..."
287
300
 
288
301
  Navigate to `https://console.cloud.google.com/apis/credentials/consent?project=PROJECT_ID`.
289
302
 
290
- Take a screenshot. If the consent screen is already configured (you see a dashboard with app info), skip to Step 6.
303
+ Take a `browser_snapshot` and `browser_screenshot`. Check the page state:
291
304
 
292
- Otherwise, work through the consent screen wizard. The wizard has multiple pages — progress through each:
305
+ ### If the consent screen is already configured
293
306
 
294
- **App information page:**
295
- - Select "External" user type if prompted
296
- - App name: "Vellum Assistant"
297
- - User support email: select the user's email (this may be a dropdown or text input — adapt to what you see)
298
- - Developer contact email: enter the user's email
299
- - Submit / Save and Continue
307
+ You'll see a dashboard showing the app name ("Vellum Assistant" or similar) with an "Edit App" button. **Skip to Step 6.**
300
308
 
301
- **Scopes page:**
302
- - Add these scopes:
303
- - `https://www.googleapis.com/auth/gmail.readonly`
304
- - `https://www.googleapis.com/auth/gmail.modify`
305
- - `https://www.googleapis.com/auth/gmail.send`
306
- - `https://www.googleapis.com/auth/calendar.readonly`
307
- - `https://www.googleapis.com/auth/calendar.events`
308
- - `https://www.googleapis.com/auth/userinfo.email`
309
- - Save and Continue
309
+ ### If you see a user type selection (External / Internal)
310
310
 
311
- **Test users page:**
312
- - Add the user's email as a test user
313
- - Save and Continue
311
+ Select **"External"** and click **Create** or **Get Started**.
314
312
 
315
- **Summary page:**
316
- - Return to dashboard
313
+ ### Consent screen form (wizard or single-page)
317
314
 
318
- **Verify:** The consent screen dashboard shows "Vellum Assistant" with the configured scopes.
315
+ Google Cloud uses either a multi-page wizard or a single-page form. Adapt to what you see:
319
316
 
320
- ## Step 6: Create OAuth Credentials and Capture Both Client ID and Secret
317
+ **App information section:**
318
+ - **App name**: Type "Vellum Assistant" in the app name field.
319
+ - **User support email**: This is typically a dropdown showing the signed-in user's email. Use `browser_snapshot` to find a `<select>` or clickable dropdown element near "User support email". Select the user's email.
320
+ - **Developer contact email**: Type the user's email into this field. (Use the same email visible in the support email dropdown if you can read it, or use `browser_extract` to find the email shown on the page.)
321
+ - Click **Save and Continue** if on a multi-page wizard.
321
322
 
322
- **Goal:** A "Desktop app" OAuth client exists, and both its Client ID and Client Secret are stored in the vault.
323
+ **Scopes section:**
324
+ - Click **"Add or Remove Scopes"** (or similar button).
325
+ - In the scope picker dialog, look for a text input labeled **"Manually add scopes"** or **"Filter"** at the bottom or top of the dialog.
326
+ - Paste all 6 scopes at once as a comma-separated string into that input:
327
+ ```
328
+ https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.send,https://www.googleapis.com/auth/calendar.readonly,https://www.googleapis.com/auth/calendar.events,https://www.googleapis.com/auth/userinfo.email
329
+ ```
330
+ - Click **"Add to Table"** or **"Update"** to confirm the scopes.
331
+ - If no manual input is available, you'll need to search for and check each scope individually using the scope tree. Search for each scope URL in the filter box and check its checkbox.
332
+ - Click **Save and Continue** (or **Update** then **Save and Continue**).
323
333
 
324
- ### CRITICAL — Credential Capture Protocol
334
+ **Test users section:**
335
+ - Click **"Add Users"** or similar.
336
+ - Enter the user's email address.
337
+ - Click **Add** then **Save and Continue**.
325
338
 
326
- When you create the OAuth client, Google shows a **single dialog** with the Client ID, Client Secret, and a Download button. You MUST follow this exact sequence — **no improvisation**:
339
+ **Summary section:**
340
+ - Click **"Back to Dashboard"** or **"Submit"**.
327
341
 
328
- 1. Read the **Client ID** from the screen (it is visible and safe to read).
329
- 2. Store the Client ID via `credential_store store`.
330
- 3. **IMMEDIATELY** present a `credential_store prompt` for the Client Secret. This is your ONLY next action after storing the Client ID. Do not attempt anything else.
331
- 4. Wait for the user to paste the secret.
342
+ **What you should see when done:** A consent screen dashboard showing "Vellum Assistant" as the app name.
332
343
 
333
- **Absolute prohibitions during this step:**
334
- - Do NOT click the Download button. There is no JSON file. Downloads do not work.
335
- - Do NOT try to read the Client Secret from the screenshot. It is visible on screen but must come from the user via secure prompt to ensure accuracy.
336
- - Do NOT navigate away from the dialog, close it, or interact with any other element until the user has pasted the secret.
337
- - Do NOT mention JSON files, downloads, or `~/Downloads` to the user — none of these exist.
344
+ Tell the user: "Consent screen configured!"
338
345
 
339
- ### 6a: Create the credential
346
+ ## Step 6: Create OAuth Credentials and Capture Them
347
+
348
+ **Goal:** A "Desktop app" OAuth client exists, and both its Client ID and Client Secret are stored in the vault.
340
349
 
341
350
  Tell the user: "Creating OAuth credentials..."
342
351
 
352
+ ### 6a: Create the credential
353
+
343
354
  Navigate to `https://console.cloud.google.com/apis/credentials?project=PROJECT_ID`.
344
355
 
345
- Find the option to create new credentials (typically a button labeled "Create Credentials" or similar), then select "OAuth client ID" from the menu.
356
+ Take a `browser_snapshot`. Find and click a button labeled **"Create Credentials"** or **"+ Create Credentials"**. A dropdown menu should appear — take another snapshot and click **"OAuth client ID"**.
346
357
 
347
- On the creation form:
348
- - Application type: **Desktop app**
349
- - Name: "Vellum Assistant"
350
- - Do NOT add any redirect URIs for the desktop app flow
358
+ On the creation form (take a snapshot to see the fields):
359
+ - **Application type**: Find the dropdown and select **"Desktop app"**. This may be a `<select>` element or a custom dropdown — use the snapshot to identify it. You might need to click the dropdown first, then take another snapshot to see the options, then click "Desktop app".
360
+ - **Name**: Type "Vellum Assistant" in the name field.
361
+ - Do NOT add any redirect URIs the desktop app flow doesn't need them.
351
362
 
352
- Submit the form.
363
+ Click **"Create"** to submit the form.
353
364
 
354
- ### 6b: Read Client ID and IMMEDIATELY prompt for Client Secret
365
+ ### 6b: Capture credentials from the dialog
355
366
 
356
- After creation, a dialog will display the new Client ID and Client Secret. Handle **both** in this single step:
367
+ After creation, a dialog will display the **Client ID** and **Client Secret**. This is the critical step.
357
368
 
358
- **First**, read the **Client ID** from the screen. It looks like `123456789-xxxxx.apps.googleusercontent.com`. Store it:
369
+ **First**, try to auto-read the **Client ID** using `browser_extract`. The Client ID matches the pattern `*.apps.googleusercontent.com`. Search the extracted text for this pattern. If found, store it:
359
370
 
360
371
  ```
361
372
  credential_store store:
362
373
  service: "integration:gmail"
363
374
  field: "client_id"
364
- value: "<the Client ID you read from the screen>"
375
+ value: "<the Client ID extracted from the page>"
365
376
  ```
366
377
 
367
- **Then IMMEDIATELY** with no other actions in between — tell the user:
378
+ If `browser_extract` fails to find the Client ID, prompt the user instead:
368
379
 
369
- > "Got the Client ID! Now I need the Client Secret. In the dialog still open in the browser, you'll see the **Client Secret** value (starts with `GOCSPX-`). Please copy it and paste it into the secure prompt below."
380
+ ```
381
+ credential_store prompt:
382
+ service: "integration:gmail"
383
+ field: "client_id"
384
+ label: "Google OAuth Client ID"
385
+ description: "Copy the Client ID from the dialog in the Chrome window and paste it here. It looks like 123456789-xxxxx.apps.googleusercontent.com"
386
+ placeholder: "xxxxx.apps.googleusercontent.com"
387
+ ```
388
+
389
+ **Then** — whether the Client ID was auto-read or prompted — tell the user:
390
+
391
+ > "Got the Client ID! Now I need the Client Secret. You can see it in the dialog in the Chrome window — it starts with `GOCSPX-`. Please copy it and paste it into the secure prompt below."
370
392
 
371
393
  And present the secure prompt:
372
394
 
@@ -379,17 +401,19 @@ credential_store prompt:
379
401
  placeholder: "GOCSPX-..."
380
402
  ```
381
403
 
382
- Wait for the user to complete the prompt. Do not take any other action until they do.
404
+ Wait for the user to complete the prompt. **Do not take any other browser actions until the user has pasted the secret.** The dialog must stay open so they can see and copy the value.
383
405
 
384
- If the user has trouble locating the secret, take a `browser_screenshot` and help them find it on the page — but do NOT attempt to read the secret value yourself.
406
+ If the user has trouble locating the secret, take a `browser_screenshot` and describe where the secret field is on the screen — but do NOT attempt to read the secret value yourself. It must come from the user for accuracy.
385
407
 
386
- **Verify:** `credential_store list` shows both `client_id` and `client_secret` for `integration:gmail`.
408
+ **What you should see when done:** `credential_store list` shows both `client_id` and `client_secret` for `integration:gmail`.
409
+
410
+ Tell the user: "Credentials stored securely!"
387
411
 
388
412
  ## Step 7: OAuth2 Authorization
389
413
 
390
414
  **Goal:** The user authorizes Vellum to access their Gmail and Calendar via OAuth.
391
415
 
392
- Tell the user: "Opening Google sign-in so you can authorize Vellum. Just click 'Allow' on the consent page."
416
+ Tell the user: "Opening Google authorization just click 'Allow' on the consent page."
393
417
 
394
418
  Use `credential_store` with:
395
419
 
@@ -400,19 +424,19 @@ service: "integration:gmail"
400
424
 
401
425
  This auto-reads client_id and client_secret from the secure store and auto-fills auth_url, token_url, scopes, and extra_params from well-known config.
402
426
 
403
- **If the user sees a "This app isn't verified" warning:** Tell them this is normal for apps in testing mode. Click "Advanced" then "Go to Vellum Assistant (unsafe)" to proceed.
427
+ **If the user sees a "This app isn't verified" warning:** Tell them: "You'll see an 'app isn't verified' warning — this is normal for personal apps in testing mode. Click **Advanced**, then **Go to Vellum Assistant (unsafe)** to proceed."
404
428
 
405
429
  **Verify:** The `oauth2_connect` call returns a success message with the connected account email.
406
430
 
407
431
  ## Step 8: Done!
408
432
 
409
- "**Gmail and Calendar are connected!** You can now read, search, and send emails, plus view and manage your calendar. Try asking me to check your inbox or show your upcoming events!"
433
+ Tell the user: "**Gmail and Calendar are connected!** You can now read, search, and send emails, plus view and manage your calendar. Try asking me to check your inbox or show your upcoming events!"
410
434
 
411
435
  ## Error Handling
412
436
 
413
437
  - **Page load failures:** Retry navigation once. If it still fails, tell the user and ask them to check their internet connection.
414
438
  - **Permission errors in GCP:** The user may need billing enabled or organization-level permissions. Explain clearly and ask them to resolve it.
415
439
  - **Consent screen already configured:** Don't overwrite — skip to credential creation.
416
- - **Element not found:** Take a fresh screenshot to re-assess. The GCP UI may have changed. Describe what you see and try alternative approaches. If stuck after 2 attempts, ask the user for guidance.
440
+ - **Element not found:** Take a fresh `browser_snapshot` to re-assess. The GCP UI may have changed. Describe what you see and try alternative approaches. If stuck after 2 attempts, ask the user for guidance — they can see the Chrome window too.
417
441
  - **OAuth flow timeout or failure:** Offer to retry. The credentials are already stored, so reconnecting only requires re-running the authorization flow.
418
442
  - **Any unexpected state:** Take a `browser_screenshot`, describe what you see, and ask the user for guidance.