@agent-native/core 0.146.0 → 0.146.1

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 (112) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +4 -0
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  4. package/corpus/templates/analytics/actions/compose-dashboard.ts +2 -27
  5. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +7 -8
  6. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +18 -2
  7. package/corpus/templates/analytics/actions/mutate-dashboard.ts +16 -24
  8. package/corpus/templates/analytics/actions/rename-dashboard.ts +2 -24
  9. package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +2 -24
  10. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +2 -25
  11. package/corpus/templates/analytics/actions/update-dashboard.ts +4 -32
  12. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +1 -40
  13. package/corpus/templates/analytics/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-comm.md +6 -0
  14. package/corpus/templates/analytics/netlify.toml +7 -0
  15. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +13 -13
  16. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +4 -2
  17. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +0 -35
  18. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +5 -3
  19. package/corpus/templates/analytics/server/lib/dashboard-collab-sync.ts +77 -0
  20. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +2 -23
  21. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +28 -74
  22. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +5 -9
  23. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +4 -0
  24. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  25. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +4 -0
  26. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  27. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +4 -0
  28. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  29. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
  30. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  31. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +4 -0
  32. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  33. package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
  34. package/corpus/templates/clips/changelog/2026-08-07-fixed-trimmed-clips-durations-so-the-main-player-display-mat.md +6 -0
  35. package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +1 -1
  36. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  37. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +4 -0
  38. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  39. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +4 -0
  40. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  41. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +4 -0
  42. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  43. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +4 -0
  44. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  45. package/corpus/templates/dispatch/changelog/2026-08-07-language-selection-now-lives-in-settings-instead-of-the-disp.md +6 -0
  46. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +4 -0
  47. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  48. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +59 -22
  49. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +4 -0
  50. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  51. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +4 -0
  52. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  53. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +4 -0
  54. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  55. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +4 -0
  56. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  57. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +10 -1
  58. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +10 -3
  59. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +4 -0
  60. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  61. package/corpus/templates/slides/actions/generate-image-api.ts +123 -0
  62. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -2
  63. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
  64. package/corpus/templates/slides/changelog/2026-08-07-deleting-a-deck-no-longer-freezes-the-slides-browser.md +6 -0
  65. package/corpus/templates/slides/changelog/2026-08-07-slides-verify-generated-images-are-persisted-on-the-target-s.md +6 -0
  66. package/corpus/templates/slides/server/lib/slide-image-insertion.ts +141 -0
  67. package/corpus/templates/slides/server/plugins/agent-chat.ts +2 -0
  68. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +4 -0
  69. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  70. package/dist/client/AgentPanel.d.ts +10 -4
  71. package/dist/client/AgentPanel.js +29 -82
  72. package/dist/collab/awareness.d.ts +2 -2
  73. package/dist/collab/struct-routes.d.ts +1 -1
  74. package/dist/db/migrations.js +22 -4
  75. package/dist/deploy/build.d.ts +1 -0
  76. package/dist/deploy/build.js +27 -22
  77. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  78. package/dist/notifications/routes.d.ts +1 -1
  79. package/dist/observability/routes.d.ts +1 -1
  80. package/dist/resources/handlers.d.ts +1 -1
  81. package/dist/server/builder-browser.d.ts +34 -0
  82. package/dist/server/builder-browser.js +179 -0
  83. package/dist/server/core-routes-plugin.d.ts +5 -0
  84. package/dist/server/core-routes-plugin.js +24 -8
  85. package/dist/server/index.d.ts +1 -1
  86. package/dist/server/index.js +1 -1
  87. package/dist/shared/cache-control.d.ts +2 -2
  88. package/dist/shared/cache-control.js +2 -2
  89. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
  90. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  91. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +4 -0
  92. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  93. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +4 -0
  94. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  95. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +4 -0
  96. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  97. package/dist/vite/client.js +13 -1
  98. package/docs/content/drop-in-agent.mdx +3 -3
  99. package/docs/content/getting-started-actions.mdx +1 -2
  100. package/docs/content/getting-started-pages.mdx +1 -2
  101. package/docs/content/getting-started.mdx +0 -4
  102. package/docs/content/what-is-agent-native.mdx +4 -4
  103. package/package.json +3 -3
  104. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +4 -0
  105. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  106. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +4 -0
  107. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  108. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +4 -0
  109. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  110. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +4 -0
  111. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -0
  112. package/docs/content/getting-started-database.mdx +0 -173
@@ -115,40 +115,10 @@ function fixed(sql: string): (window?: MetricWindow) => string {
115
115
 
116
116
  const TEMPLATE_EXPR =
117
117
  "COALESCE(NULLIF(template, ''), NULLIF(properties::jsonb ->> 'templateId', ''), NULLIF(properties::jsonb ->> 'agent_native_template', ''), NULLIF(properties::jsonb ->> 'agentNativeTemplate', ''), NULLIF(app, ''), NULLIF(properties::jsonb ->> 'agent_native_app', ''), NULLIF(properties::jsonb ->> 'agentNativeApp', ''), 'unknown')";
118
- /**
119
- * The built-in traffic dashboard is about the shipped core apps, not every
120
- * host or preview artifact that can share the browser analytics key.
121
- *
122
- * Keep this aligned with `coreTemplates()` in the shared app catalog. The
123
- * analytics template is deliberately self-contained at runtime, so its
124
- * production bundle does not depend on another workspace package being built
125
- * before this template.
126
- */
127
- export const FIRST_PARTY_TEMPLATE_NAMES = [
128
- "analytics",
129
- "assets",
130
- "brain",
131
- "calendar",
132
- "chat",
133
- "clips",
134
- "content",
135
- "design",
136
- "dispatch",
137
- "forms",
138
- "mail",
139
- "plan",
140
- "slides",
141
- ] as const;
142
- const FIRST_PARTY_TEMPLATE_SQL_LIST = FIRST_PARTY_TEMPLATE_NAMES.map(
143
- (name) => `'${name}'`,
144
- ).join(", ");
145
- const FIRST_PARTY_TEMPLATE_FILTER = `lower(${TEMPLATE_EXPR}) IN (${FIRST_PARTY_TEMPLATE_SQL_LIST})`;
146
118
  const KNOWN_TEMPLATE_FILTER = `${TEMPLATE_EXPR} <> 'unknown'`;
147
119
  const PRODUCT_ACTIVITY_TEMPLATE_FILTER = `lower(${TEMPLATE_EXPR}) <> 'docs'`;
148
120
  const MARKETING_SITE_TEMPLATE_FILTER = `lower(${TEMPLATE_EXPR}) <> 'www'`;
149
121
  const KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER = `${KNOWN_TEMPLATE_FILTER} AND ${PRODUCT_ACTIVITY_TEMPLATE_FILTER}`;
150
- const FIRST_PARTY_PRODUCT_ACTIVITY_TEMPLATE_FILTER = `${PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER}`;
151
- const FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER = `${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER}`;
152
122
  const EVENT_DATE_SQL = "event_date";
153
123
  const EVENT_DATE_FILTER_SQL = EVENT_DATE_SQL;
154
124
  const USER_KEY_SQL = "NULLIF(user_key, '')";
@@ -255,7 +225,7 @@ const TOTAL_SIGNUPS_SQL = `SELECT COUNT(*) AS signups FROM analytics_events WHER
255
225
  const LEGACY_SEED_SIGNUPS_TIME_RANGE_FILTER = `('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND ${EVENT_DATE_SQL} >= ${daysAgoSql(7)}) OR ('{{timeRange}}' = '30d' AND ${EVENT_DATE_SQL} >= ${daysAgoSql(30)}) OR ('{{timeRange}}' = '90d' AND ${EVENT_DATE_SQL} >= ${daysAgoSql(90)}) OR ('{{timeRange}}' = '180d' AND ${EVENT_DATE_SQL} >= ${daysAgoSql(180)}) OR ('{{timeRange}}' = '365d' AND ${EVENT_DATE_SQL} >= ${daysAgoSql(365)}))`;
256
226
  export const LEGACY_SEED_SIGNUPS_OVER_TIME_SQL = `WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY ${EVENT_DATE_SQL}) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${LEGACY_SEED_SIGNUPS_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
257
227
  export const LEGACY_SIGNUPS_OVER_TIME_SQL = `WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY ${EVENT_DATE_SQL}) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
258
- export const SIGNUPS_OVER_TIME_SQL = `WITH digits AS (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9), offsets AS (SELECT ones.n + tens.n * 10 + hundreds.n * 100 AS n FROM digits ones CROSS JOIN digits tens CROSS JOIN digits hundreds WHERE hundreds.n < 8), signup_events AS (SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
228
+ export const SIGNUPS_OVER_TIME_SQL = `WITH digits AS (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9), offsets AS (SELECT ones.n + tens.n * 10 + hundreds.n * 100 AS n FROM digits ones CROSS JOIN digits tens CROSS JOIN digits hundreds WHERE hundreds.n < 8), signup_events AS (SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
259
229
  export const LEGACY_RETENTION_OVER_TIME_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, MIN(event_date) AS cohort_date FROM base GROUP BY user_key), anchor_dates AS (SELECT DISTINCT cohort_date AS date FROM first_seen WHERE cohort_date <= ${daysAgoSql(14)} AND ${dashboardTimeRangeFilter("cohort_date")}), cohort_windows AS (SELECT a.date, f.user_key, f.cohort_date FROM anchor_dates a JOIN first_seen f ON f.cohort_date >= ${rollingWindowStartSql()} AND f.cohort_date <= a.date), cohort_sizes AS (SELECT date, COUNT(DISTINCT user_key) AS users FROM cohort_windows GROUP BY date), periods AS (SELECT '1-7d return' AS period UNION ALL SELECT '7-14d return' AS period), retained AS (SELECT cw.date, '1-7d return' AS period, COUNT(DISTINCT cw.user_key) AS retained FROM cohort_windows cw JOIN base b ON b.user_key = cw.user_key AND b.event_date > cw.cohort_date AND b.event_date <= to_char(cw.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') GROUP BY cw.date UNION ALL SELECT cw.date, '7-14d return' AS period, COUNT(DISTINCT cw.user_key) AS retained FROM cohort_windows cw JOIN base b ON b.user_key = cw.user_key AND b.event_date >= to_char(cw.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') AND b.event_date <= to_char(cw.cohort_date::date + INTERVAL '14 days', 'YYYY-MM-DD') GROUP BY cw.date) SELECT cs.date, p.period, COALESCE(r.retained, 0) AS retained_users, cs.users AS cohort_users, COALESCE(r.retained::float / NULLIF(cs.users, 0), 0) AS rate FROM cohort_sizes cs CROSS JOIN periods p LEFT JOIN retained r ON r.date = cs.date AND r.period = p.period WHERE cs.users >= ${RETENTION_MIN_COHORT_SIZE} ORDER BY cs.date, p.period`;
260
230
  export const LEGACY_ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER}), ranked_first_seen AS (SELECT user_key, template, event_date AS cohort_date, ROW_NUMBER() OVER (PARTITION BY user_key ORDER BY event_date, template) AS rn FROM base), first_seen AS (SELECT user_key, template, cohort_date FROM ranked_first_seen WHERE rn = 1), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= ${daysAgoSql(7)} AND ${dashboardTimeRangeFilter("cohort_date")}), cohort_sizes AS (SELECT template, COUNT(DISTINCT user_key) AS users FROM cohorts GROUP BY template), retained AS (SELECT c.template, COUNT(DISTINCT c.user_key) AS retained FROM cohorts c JOIN base b ON b.user_key = c.user_key AND b.event_date > c.cohort_date AND b.event_date <= to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') GROUP BY c.template) SELECT cs.template, COALESCE(r.retained, 0) AS retained_users, cs.users AS cohort_users, COALESCE(r.retained::float / NULLIF(cs.users, 0), 0) AS rate FROM cohort_sizes cs LEFT JOIN retained r ON r.template = cs.template WHERE cs.users >= ${PER_TEMPLATE_RETENTION_MIN_COHORT_SIZE} ORDER BY rate DESC, cs.users DESC, cs.template`;
261
231
  export const LEGACY_SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER}), ranked_first_seen AS (SELECT user_key, template, event_date AS cohort_date, ROW_NUMBER() OVER (PARTITION BY user_key ORDER BY event_date, template) AS rn FROM base), first_seen AS (SELECT user_key, template, cohort_date FROM ranked_first_seen WHERE rn = 1), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= ${daysAgoSql(14)} AND ${dashboardTimeRangeFilter("cohort_date")}), cohort_sizes AS (SELECT template, COUNT(DISTINCT user_key) AS users FROM cohorts GROUP BY template), retained AS (SELECT c.template, COUNT(DISTINCT c.user_key) AS retained FROM cohorts c JOIN base b ON b.user_key = c.user_key AND b.event_date >= to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') AND b.event_date <= to_char(c.cohort_date::date + INTERVAL '14 days', 'YYYY-MM-DD') GROUP BY c.template) SELECT cs.template, COALESCE(r.retained, 0) AS retained_users, cs.users AS cohort_users, COALESCE(r.retained::float / NULLIF(cs.users, 0), 0) AS rate FROM cohort_sizes cs LEFT JOIN retained r ON r.template = cs.template WHERE cs.users >= ${PER_TEMPLATE_RETENTION_MIN_COHORT_SIZE} ORDER BY rate DESC, cs.users DESC, cs.template`;
@@ -289,11 +259,7 @@ export const LEGACY_V0_ONE_DAY_RETENTION_BY_TEMPLATE_SQL =
289
259
  "CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD'))))",
290
260
  "CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))",
291
261
  );
292
- export const LEGACY_SIGNUPS_BY_TEMPLATE_SQL = `SELECT ${TEMPLATE_EXPR} AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${TEMPLATE_EXPR} ORDER BY count DESC`;
293
- export const SIGNUPS_BY_TEMPLATE_SQL = `${LEGACY_SIGNUPS_BY_TEMPLATE_SQL.replace(
294
- ` AND ${DASHBOARD_EMAIL_FILTER} GROUP BY`,
295
- ` AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER} GROUP BY`,
296
- )}`;
262
+ const SIGNUPS_BY_TEMPLATE_SQL = `SELECT ${TEMPLATE_EXPR} AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${TEMPLATE_EXPR} ORDER BY count DESC`;
297
263
  export const LEGACY_RECURRING_USERS_BY_TEMPLATE_SQL = `WITH all_users AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL}, user_id, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, MIN(event_date) AS first_date FROM all_users GROUP BY user_key) SELECT a.event_date AS date, a.template AS template, COUNT(DISTINCT a.user_key) AS users FROM all_users a JOIN first_seen f ON f.user_key = a.user_key WHERE a.event_date <> f.first_date AND a.template <> 'unknown' AND ${dashboardTimeRangeFilter("a.event_date")} GROUP BY 1, 2 ORDER BY date, template`;
298
264
  export const LEGACY_RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL = `WITH all_users AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL}, user_id, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, MIN(event_date) AS first_date FROM all_users GROUP BY user_key) SELECT to_char(date_trunc('week', a.event_date::date), 'YYYY-MM-DD') AS date, a.template AS template, COUNT(DISTINCT a.user_key) AS users FROM all_users a JOIN first_seen f ON f.user_key = a.user_key WHERE a.event_date <> f.first_date AND a.template <> 'unknown' AND ${dashboardTimeRangeFilter("a.event_date")} GROUP BY 1, 2 ORDER BY date, template`;
299
265
  const OBSERVED_ACTIVITY_LOOKBACK_FILTER = `${EVENT_DATE_SQL} >= ${daysAgoSql(OBSERVED_ACTIVITY_LOOKBACK_DAYS)}`;
@@ -325,7 +291,7 @@ export const PRE_MARKETING_SITE_RETENTION_OVER_TIME_SQL =
325
291
  const RETENTION_OVER_TIME_SQL =
326
292
  PRE_MARKETING_SITE_RETENTION_OVER_TIME_SQL.replace(
327
293
  PRODUCT_ACTIVITY_TEMPLATE_FILTER,
328
- `${FIRST_PARTY_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
294
+ `${PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
329
295
  );
330
296
  export const PRE_MARKETING_SITE_ONE_DAY_RETENTION_BY_TEMPLATE_SQL =
331
297
  LEGACY_ONE_DAY_RETENTION_BY_TEMPLATE_SQL.replace(
@@ -337,7 +303,7 @@ export const MATERIALIZED_ONE_DAY_RETENTION_BY_TEMPLATE_SQL =
337
303
  KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER,
338
304
  `${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
339
305
  );
340
- const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} GROUP BY 1, 2, 3), observed AS (SELECT user_key, event_date, FIRST_VALUE(template) OVER (PARTITION BY user_key ORDER BY event_date, template) AS starting_template, MIN(event_date) OVER (PARTITION BY user_key ORDER BY event_date, template) AS cohort_date FROM base), cohorts AS (SELECT user_key, starting_template AS template, cohort_date, MAX(CASE WHEN event_date > cohort_date AND event_date <= to_char(cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') THEN 1 ELSE 0 END) AS retained FROM observed WHERE cohort_date <= ${daysAgoSql(7)} AND ${dashboardTimeRangeFilter("cohort_date")} GROUP BY user_key, starting_template, cohort_date) SELECT template, SUM(retained) AS retained_users, COUNT(*) AS cohort_users, SUM(retained)::float / NULLIF(COUNT(*), 0) AS rate FROM cohorts GROUP BY template HAVING COUNT(*) >= ${PER_TEMPLATE_RETENTION_MIN_COHORT_SIZE} ORDER BY rate DESC, cohort_users DESC, template`;
306
+ const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} GROUP BY 1, 2, 3), observed AS (SELECT user_key, event_date, FIRST_VALUE(template) OVER (PARTITION BY user_key ORDER BY event_date, template) AS starting_template, MIN(event_date) OVER (PARTITION BY user_key ORDER BY event_date, template) AS cohort_date FROM base), cohorts AS (SELECT user_key, starting_template AS template, cohort_date, MAX(CASE WHEN event_date > cohort_date AND event_date <= to_char(cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD') THEN 1 ELSE 0 END) AS retained FROM observed WHERE cohort_date <= ${daysAgoSql(7)} AND ${dashboardTimeRangeFilter("cohort_date")} GROUP BY user_key, starting_template, cohort_date) SELECT template, SUM(retained) AS retained_users, COUNT(*) AS cohort_users, SUM(retained)::float / NULLIF(COUNT(*), 0) AS rate FROM cohorts GROUP BY template HAVING COUNT(*) >= ${PER_TEMPLATE_RETENTION_MIN_COHORT_SIZE} ORDER BY rate DESC, cohort_users DESC, template`;
341
307
  export const PRE_MARKETING_SITE_SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL =
342
308
  LEGACY_SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL.replace(
343
309
  `${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER}), ranked_first_seen`,
@@ -346,7 +312,7 @@ export const PRE_MARKETING_SITE_SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL =
346
312
  const SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL =
347
313
  PRE_MARKETING_SITE_SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL.replace(
348
314
  KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER,
349
- `${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
315
+ `${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
350
316
  );
351
317
  export const PRE_MARKETING_SITE_RECURRING_USERS_BY_TEMPLATE_SQL = `WITH first_seen AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, MIN(${EVENT_DATE_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} GROUP BY 1), activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER}) SELECT a.event_date AS date, a.template AS template, COUNT(DISTINCT a.user_key) AS users FROM activity a JOIN first_seen f ON f.user_key = a.user_key WHERE a.event_date <> f.first_date AND a.template <> 'unknown' GROUP BY 1, 2 ORDER BY date, template`;
352
318
  export const DOUBLE_SCAN_RECURRING_USERS_BY_TEMPLATE_SQL =
@@ -354,14 +320,14 @@ export const DOUBLE_SCAN_RECURRING_USERS_BY_TEMPLATE_SQL =
354
320
  PRODUCT_ACTIVITY_TEMPLATE_FILTER,
355
321
  `${PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
356
322
  );
357
- const RECURRING_USERS_BY_TEMPLATE_SQL = `WITH activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template, MIN(${EVENT_DATE_SQL}) OVER (PARTITION BY ${SIGNED_IN_ACTIVITY_KEY_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${FIRST_PARTY_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER}) SELECT event_date AS date, template, COUNT(DISTINCT user_key) AS users FROM activity WHERE event_date <> first_date AND template <> 'unknown' AND ${DASHBOARD_TIME_RANGE_FILTER} GROUP BY 1, 2 ORDER BY date, template`;
323
+ const RECURRING_USERS_BY_TEMPLATE_SQL = `WITH activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template, MIN(${EVENT_DATE_SQL}) OVER (PARTITION BY ${SIGNED_IN_ACTIVITY_KEY_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER}) SELECT event_date AS date, template, COUNT(DISTINCT user_key) AS users FROM activity WHERE event_date <> first_date AND template <> 'unknown' AND ${DASHBOARD_TIME_RANGE_FILTER} GROUP BY 1, 2 ORDER BY date, template`;
358
324
  export const PRE_MARKETING_SITE_RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL = `WITH first_seen AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, MIN(${EVENT_DATE_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} GROUP BY 1), activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER}) SELECT to_char(date_trunc('week', a.event_date::date), 'YYYY-MM-DD') AS date, a.template AS template, COUNT(DISTINCT a.user_key) AS users FROM activity a JOIN first_seen f ON f.user_key = a.user_key WHERE a.event_date <> f.first_date AND a.template <> 'unknown' GROUP BY 1, 2 ORDER BY date, template`;
359
325
  export const DOUBLE_SCAN_RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL =
360
326
  PRE_MARKETING_SITE_RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL.replace(
361
327
  PRODUCT_ACTIVITY_TEMPLATE_FILTER,
362
328
  `${PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
363
329
  );
364
- const RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL = `WITH activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template, MIN(${EVENT_DATE_SQL}) OVER (PARTITION BY ${SIGNED_IN_ACTIVITY_KEY_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${FIRST_PARTY_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER}) SELECT to_char(date_trunc('week', event_date::date), 'YYYY-MM-DD') AS date, template, COUNT(DISTINCT user_key) AS users FROM activity WHERE event_date <> first_date AND template <> 'unknown' AND ${DASHBOARD_TIME_RANGE_FILTER} GROUP BY 1, 2 ORDER BY date, template`;
330
+ const RECURRING_USERS_BY_TEMPLATE_WEEKLY_SQL = `WITH activity AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, ${EVENT_DATE_SQL} AS event_date, ${TEMPLATE_EXPR} AS template, MIN(${EVENT_DATE_SQL}) OVER (PARTITION BY ${SIGNED_IN_ACTIVITY_KEY_SQL}) AS first_date FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${OBSERVED_ACTIVITY_LOOKBACK_FILTER}) SELECT to_char(date_trunc('week', event_date::date), 'YYYY-MM-DD') AS date, template, COUNT(DISTINCT user_key) AS users FROM activity WHERE event_date <> first_date AND template <> 'unknown' AND ${DASHBOARD_TIME_RANGE_FILTER} GROUP BY 1, 2 ORDER BY date, template`;
365
331
  const LEGACY_RECURRING_USERS_DESCRIPTION =
366
332
  "Daily signed-in visitors who are NOT on their all-time first active day (Recurring only), stacked by inferred template/app used that day. Docs traffic and unknown template are excluded.";
367
333
  const LEGACY_RECURRING_USERS_WEEKLY_DESCRIPTION =
@@ -543,44 +509,20 @@ export const LEGACY_DAU_BY_TEMPLATE_SQL = `SELECT ${EVENT_DATE_SQL} AS date, ${T
543
509
  export const PRE_MARKETING_SITE_DAU_BY_TEMPLATE_SQL = `SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template, COUNT(DISTINCT user_key) AS visitors FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY ${EVENT_DATE_SQL}, ${TEMPLATE_EXPR} ORDER BY date, template`;
544
510
  const DAU_BY_TEMPLATE_SQL = PRE_MARKETING_SITE_DAU_BY_TEMPLATE_SQL.replace(
545
511
  ` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY`,
546
- ` AND ${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} GROUP BY`,
512
+ ` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} GROUP BY`,
547
513
  );
548
514
  export const LEGACY_WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS visitor_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_FILTER}), days AS (SELECT DISTINCT event_date AS date FROM base WHERE ${DASHBOARD_EVENT_DATE_RANGE_FILTER}) SELECT d.date, b.template, COUNT(DISTINCT b.visitor_key) AS visitors FROM days d JOIN base b ON b.event_date >= to_char(d.date::date - INTERVAL '6 days', 'YYYY-MM-DD') AND b.event_date <= d.date GROUP BY d.date, b.template ORDER BY d.date, b.template`;
549
515
  export const PRE_MARKETING_SITE_WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT user_key AS visitor_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_FILTER}), days AS (SELECT DISTINCT event_date AS date FROM base WHERE ${DASHBOARD_EVENT_DATE_RANGE_FILTER}) SELECT d.date, b.template, COUNT(DISTINCT b.visitor_key) AS visitors FROM days d JOIN base b ON b.event_date >= to_char(d.date::date - INTERVAL '6 days', 'YYYY-MM-DD') AND b.event_date <= d.date GROUP BY d.date, b.template ORDER BY d.date, b.template`;
550
516
  const WAU_BY_TEMPLATE_SQL = PRE_MARKETING_SITE_WAU_BY_TEMPLATE_SQL.replace(
551
517
  ` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_FILTER}`,
552
- ` AND ${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_FILTER}`,
518
+ ` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_FILTER}`,
553
519
  );
554
520
  const PRE_MARKETING_SITE_REPEAT_USERS_SQL = `WITH user_days AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS user_key, COUNT(DISTINCT ${EVENT_DATE_SQL}) AS active_days FROM analytics_events WHERE ${SIGNED_IN_PRODUCT_ACTIVITY_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${SIGNED_IN_ACTIVITY_KEY_SQL}) SELECT COUNT(*) AS count FROM user_days WHERE active_days >= 2`;
555
521
  const REPEAT_USERS_SQL = PRE_MARKETING_SITE_REPEAT_USERS_SQL.replace(
556
522
  PRODUCT_ACTIVITY_TEMPLATE_FILTER,
557
- `${FIRST_PARTY_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
523
+ `${PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER}`,
558
524
  );
559
525
 
560
- export const LEGACY_TEMPLATE_INTEREST_OVER_TIME_SQL = `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`;
561
- export const TEMPLATE_INTEREST_OVER_TIME_SQL = `${LEGACY_TEMPLATE_INTEREST_OVER_TIME_SQL.replace(
562
- ` AND ${DASHBOARD_EMAIL_FILTER} GROUP BY`,
563
- ` AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER} GROUP BY`,
564
- )}`;
565
- export const LEGACY_CLICKS_BY_TEMPLATE_SQL =
566
- LEGACY_TEMPLATE_INTEREST_OVER_TIME_SQL;
567
- const CLICKS_BY_TEMPLATE_SQL = TEMPLATE_INTEREST_OVER_TIME_SQL;
568
- export const LEGACY_DEMO_CLICKS_OVER_TIME_SQL = `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`;
569
- export const DEMO_CLICKS_OVER_TIME_SQL = `${LEGACY_DEMO_CLICKS_OVER_TIME_SQL.replace(
570
- ` AND ${DASHBOARD_EMAIL_FILTER} GROUP BY`,
571
- ` AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER} GROUP BY`,
572
- )}`;
573
- export const LEGACY_CLI_COPIES_OVER_TIME_SQL = `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`;
574
- export const CLI_COPIES_OVER_TIME_SQL = `${LEGACY_CLI_COPIES_OVER_TIME_SQL.replace(
575
- ` AND ${DASHBOARD_EMAIL_FILTER} GROUP BY`,
576
- ` AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER} GROUP BY`,
577
- )}`;
578
- export const LEGACY_PAGEVIEWS_OVER_TIME_SQL = `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') ORDER BY date, template`;
579
- export const PAGEVIEWS_OVER_TIME_SQL = `${LEGACY_PAGEVIEWS_OVER_TIME_SQL.replace(
580
- ` AND ${DASHBOARD_EMAIL_FILTER} GROUP BY`,
581
- ` AND ${DASHBOARD_EMAIL_FILTER} AND ${FIRST_PARTY_TEMPLATE_FILTER} GROUP BY`,
582
- )}`;
583
-
584
526
  /**
585
527
  * Catalog entries. Order here is the default panel order when a caller passes
586
528
  * metrics; callers can reorder by listing keys in the order they want.
@@ -803,7 +745,9 @@ const ENTRIES: FirstPartyMetric[] = [
803
745
  source: "first-party",
804
746
  width: 2,
805
747
  windowed: false,
806
- buildSql: fixed(TEMPLATE_INTEREST_OVER_TIME_SQL),
748
+ buildSql: fixed(
749
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
750
+ ),
807
751
  config: {
808
752
  xKey: "date",
809
753
  yKey: "count",
@@ -823,7 +767,9 @@ const ENTRIES: FirstPartyMetric[] = [
823
767
  source: "first-party",
824
768
  width: 2,
825
769
  windowed: false,
826
- buildSql: fixed(CLICKS_BY_TEMPLATE_SQL),
770
+ buildSql: fixed(
771
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click template' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
772
+ ),
827
773
  config: {
828
774
  xKey: "date",
829
775
  yKey: "count",
@@ -843,7 +789,9 @@ const ENTRIES: FirstPartyMetric[] = [
843
789
  source: "first-party",
844
790
  width: 2,
845
791
  windowed: false,
846
- buildSql: fixed(DEMO_CLICKS_OVER_TIME_SQL),
792
+ buildSql: fixed(
793
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'click try demo' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
794
+ ),
847
795
  config: {
848
796
  xKey: "date",
849
797
  yKey: "count",
@@ -863,7 +811,9 @@ const ENTRIES: FirstPartyMetric[] = [
863
811
  source: "first-party",
864
812
  width: 2,
865
813
  windowed: false,
866
- buildSql: fixed(CLI_COPIES_OVER_TIME_SQL),
814
+ buildSql: fixed(
815
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
816
+ ),
867
817
  config: {
868
818
  xKey: "date",
869
819
  yKey: "count",
@@ -883,7 +833,9 @@ const ENTRIES: FirstPartyMetric[] = [
883
833
  source: "first-party",
884
834
  width: 2,
885
835
  windowed: false,
886
- buildSql: fixed(CLI_COPIES_OVER_TIME_SQL),
836
+ buildSql: fixed(
837
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'copy cli command' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), 'unknown') ORDER BY date, template`,
838
+ ),
887
839
  config: {
888
840
  xKey: "date",
889
841
  yKey: "count",
@@ -907,7 +859,9 @@ const ENTRIES: FirstPartyMetric[] = [
907
859
  windowed: false,
908
860
  // Browser telemetry emits explicit `pageview` events with URL context, so
909
861
  // keep pageview panels scoped to that event instead of all tracked events.
910
- buildSql: fixed(PAGEVIEWS_OVER_TIME_SQL),
862
+ buildSql: fixed(
863
+ `SELECT ${EVENT_DATE_SQL} AS date, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'pageview' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${EVENT_DATE_SQL}, COALESCE(NULLIF(template, ''), NULLIF(app, ''), 'unknown') ORDER BY date, template`,
864
+ ),
911
865
  config: {
912
866
  xKey: "date",
913
867
  yKey: "count",
@@ -93,13 +93,11 @@ export default defineEventHandler(async (event) => {
93
93
  setResponseStatus(event, 403);
94
94
  return { error: "Invalid or expired agent access token" };
95
95
  }
96
- return buildDashboardSeedAgentContext(
97
- id,
96
+ const config =
98
97
  id === FIRST_PARTY_DASHBOARD_ID
99
98
  ? repairCanonicalFirstPartyDashboardQueries(seed).config
100
- : seed,
101
- { includeConfig: true },
102
- );
99
+ : seed;
100
+ return buildDashboardSeedAgentContext(id, config, { includeConfig: true });
103
101
  }
104
102
 
105
103
  if (!row) {
@@ -114,15 +112,13 @@ export default defineEventHandler(async (event) => {
114
112
 
115
113
  const dashboard = rowToDashboard(row);
116
114
  return buildDashboardAgentContext(
117
- id === FIRST_PARTY_DASHBOARD_ID
115
+ dashboard.id === FIRST_PARTY_DASHBOARD_ID
118
116
  ? {
119
117
  ...dashboard,
120
118
  config: repairCanonicalFirstPartyDashboardQueries(dashboard.config)
121
119
  .config,
122
120
  }
123
121
  : dashboard,
124
- {
125
- includeConfig: true,
126
- },
122
+ { includeConfig: true },
127
123
  );
128
124
  });
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -1731,7 +1731,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1731
1731
  <CenterPlaybackOverlay
1732
1732
  mode={centerOverlayMode}
1733
1733
  label={centerOverlayLabel}
1734
- durationMs={resolvedDurationMs}
1734
+ durationMs={scrubberTimeline.durationMs}
1735
1735
  speed={speed}
1736
1736
  playError={playError}
1737
1737
  onPlay={() => {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-07
4
+ ---
5
+
6
+ Fixed trimmed Clips durations so the main player display matches the edited timeline
@@ -56,7 +56,7 @@ Upload the generated artifact (the version matches `public/manifest.json`; the
56
56
  Chrome Web Store requires each upload to use a higher version than the last):
57
57
 
58
58
  ```txt
59
- templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.2.zip
59
+ templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.18.zip
60
60
  ```
61
61
 
62
62
  ## Web App Rollout Gate
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "name": "Agent-Native Clips",
4
4
  "short_name": "Clips",
5
- "version": "0.1.17",
5
+ "version": "0.1.18",
6
6
  "description": "Start Clips recordings from Chrome, capture optional diagnostics, and preview Clips links on GitHub.",
7
7
  "minimum_chrome_version": "116",
8
8
  "action": {
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.
@@ -50,6 +50,14 @@ skills. For a ChatGPT Project or any host that exposes only the MCP connector,
50
50
  also place the skill instructions or this reference in the Project
51
51
  instructions/knowledge files. Then add and authenticate the Dispatch MCP
52
52
  connector from the packaged `adapters/chatgpt-mcp/connector.json`.
53
+ This single connector is enough: Dispatch provisions or reuses the Builder
54
+ project through the Builder Projects API, so do not ask the user to add a
55
+ separate Builder CMS MCP for app creation.
56
+ Builder's separate Fusion MCP is available as a custom remote connector at
57
+ `https://mcp.builder.io/mcp/fusion` for direct Builder work. It can run an
58
+ existing project, but it cannot provision the repo-backed Agent-Native
59
+ workspace project, so it is optional and not a replacement for the Dispatch
60
+ handoff in this skill. Do not add Builder's CMS MCP for this workflow.
53
61
 
54
62
  For Claude Web, ChatGPT Web, and their web Projects, the host is an
55
63
  orchestrator, not the build environment. After forming the source brief, call
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: changed
3
+ date: 2026-08-07
4
+ ---
5
+
6
+ Language selection now lives in Settings instead of the Dispatch header.
@@ -27,6 +27,10 @@ The build location depends on the host. Treat this as a hard routing rule:
27
27
  `resourceIds` when available. This is the Builder handoff.
28
28
  - Do not substitute the generic `create_workspace_app` MCP tool in an online
29
29
  host. That tool is a local workspace scaffolder, not the Builder handoff.
30
+ - Connect the Agent-Native Dispatch MCP connector only. Dispatch uses the
31
+ authenticated Builder Projects API to reuse or provision the workspace
32
+ project before starting the Builder Cloud Agent; a separate Builder CMS MCP
33
+ connection is not required for this workflow.
30
34
  - If `start-workspace-app-creation` is not available or Dispatch is not
31
35
  authenticated, stop with the connector setup needed. Do not fall back to a
32
36
  local build or claim that the app exists.