@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
@@ -23,7 +23,7 @@ import { INTEGRATION_RECOVERY_RUNTIME_MARKER, INTEGRATION_RETRY_SWEEP_PATH, INTE
23
23
  import { isValidCron } from "../jobs/cron.js";
24
24
  import { RECURRING_JOBS_SWEEP_PATH, RECURRING_JOBS_SWEEP_TOKEN_SUBJECT, } from "../jobs/scheduler-dispatch.js";
25
25
  import { normalizeAppBasePath } from "../server/app-base-path.js";
26
- import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, } from "../shared/cache-control.js";
26
+ import { DEFAULT_SPECULATION_RULES_PATH, resolveSsrCacheHeaders, resolveSsrCacheKeyHeaders, } from "../shared/cache-control.js";
27
27
  import { mcpEmbedStaticAssetRouteRules } from "../shared/mcp-embed-headers.js";
28
28
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, } from "../shared/social-meta.js";
29
29
  import { generateActionRegistryForProject } from "../vite/action-types-plugin.js";
@@ -652,6 +652,7 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
652
652
  // The worker ships as a static bundle with no access to runtime env, so the
653
653
  // deployment-wide SSR cache policy is baked in from this build's env.
654
654
  const ssrCacheHeaders = resolveSsrCacheHeaders();
655
+ const ssrCacheKeyHeaders = resolveSsrCacheKeyHeaders();
655
656
  const routeImports = [];
656
657
  const routeRegistrations = [];
657
658
  for (let i = 0; i < routes.length; i++) {
@@ -971,9 +972,8 @@ function injectHeadScript(html, script) {
971
972
  }
972
973
 
973
974
  // Resolved from AGENT_NATIVE_SSR_CACHE at build time.
974
- const SSR_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cache-control"])};
975
- const SSR_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["cdn-cache-control"])};
976
- const SSR_NETLIFY_CDN_CACHE_CONTROL = ${JSON.stringify(ssrCacheHeaders["netlify-cdn-cache-control"])};
975
+ const SSR_CACHE_HEADERS = ${JSON.stringify(ssrCacheHeaders)};
976
+ const SSR_CACHE_KEY_HEADERS = ${JSON.stringify(ssrCacheKeyHeaders)};
977
977
  const DEFAULT_SPECULATION_RULES_PATH = ${JSON.stringify(DEFAULT_SPECULATION_RULES_PATH)};
978
978
  const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
979
979
  const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify([...new Set(immutableAssetPaths)].sort())});
@@ -1057,13 +1057,12 @@ function applyDefaultSsrCacheHeader(headers, status, pathname) {
1057
1057
  else headers.delete("vary");
1058
1058
  }
1059
1059
 
1060
- headers.set("cache-control", SSR_CACHE_CONTROL);
1061
- headers.set("cdn-cache-control", SSR_CDN_CACHE_CONTROL);
1062
- // Netlify function responses are dynamic by default and can otherwise show
1063
- // Cache-Status fwd=bypass even with Cache-Control: public. Keep this
1064
- // Netlify-specific header so SSR HTML/.data are served from the shared
1065
- // durable CDN cache instead of stampeding origin — for every visitor.
1066
- headers.set("netlify-cdn-cache-control", SSR_NETLIFY_CDN_CACHE_CONTROL);
1060
+ for (const [name, value] of Object.entries(SSR_CACHE_HEADERS)) {
1061
+ headers.set(name, value);
1062
+ }
1063
+ for (const [name, value] of Object.entries(SSR_CACHE_KEY_HEADERS)) {
1064
+ headers.set(name, value);
1065
+ }
1067
1066
  }
1068
1067
 
1069
1068
  function applyDefaultSpeculationRulesHeader(headers, status, basePath) {
@@ -3464,6 +3463,22 @@ function createBrowserOnlyServerStubPlugin() {
3464
3463
  },
3465
3464
  };
3466
3465
  }
3466
+ export function resolveNitroBuildReplacements(env = process.env) {
3467
+ return {
3468
+ // Netlify exposes DEPLOY_ID only while building. Embed it into the Nitro
3469
+ // function so preview OAuth relays can target this immutable deployment
3470
+ // even though the value is unavailable in the function runtime.
3471
+ "process.env.AGENT_NATIVE_BUILD_ID": JSON.stringify(env.DEPLOY_ID?.trim() || env.AGENT_NATIVE_BUILD_ID?.trim() || ""),
3472
+ "process.env.AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID": JSON.stringify(env.GA_MEASUREMENT_ID?.trim() || ""),
3473
+ "process.env.AGENT_NATIVE_BUILD_GTM_CONTAINER_ID": JSON.stringify(env.GTM_CONTAINER_ID?.trim() || ""),
3474
+ // Netlify's netlify.toml environment is available while this deploy
3475
+ // build runs, but is not injected into the deployed Function. Nitro is
3476
+ // a separate server build, so embed release migration ownership here as
3477
+ // well as in the Vite server bundle.
3478
+ "process.env.AGENT_NATIVE_RELEASE_MIGRATIONS": JSON.stringify(env.AGENT_NATIVE_RELEASE_MIGRATIONS?.trim() || ""),
3479
+ "process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(env.CONTEXT?.trim() || ""),
3480
+ };
3481
+ }
3467
3482
  async function buildWithNitro() {
3468
3483
  console.log(`[deploy] Building for preset "${preset}" via Nitro...`);
3469
3484
  const appBasePath = normalizeConfiguredAppBasePath();
@@ -3547,17 +3562,7 @@ export default bundle;
3547
3562
  virtual: {
3548
3563
  "virtual:agents-bundle": agentsBundleModuleSource,
3549
3564
  },
3550
- replace: {
3551
- // Netlify exposes DEPLOY_ID only while building. Embed it into the Nitro
3552
- // function so preview OAuth relays can target this immutable deployment
3553
- // even though the value is unavailable in the function runtime.
3554
- "process.env.AGENT_NATIVE_BUILD_ID": JSON.stringify(process.env.DEPLOY_ID?.trim() ||
3555
- process.env.AGENT_NATIVE_BUILD_ID?.trim() ||
3556
- ""),
3557
- "process.env.AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID": JSON.stringify(process.env.GA_MEASUREMENT_ID?.trim() || ""),
3558
- "process.env.AGENT_NATIVE_BUILD_GTM_CONTAINER_ID": JSON.stringify(process.env.GTM_CONTAINER_ID?.trim() || ""),
3559
- "process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(process.env.CONTEXT?.trim() || ""),
3560
- },
3565
+ replace: resolveNitroBuildReplacements(),
3561
3566
  // Replace browser-only renderers (Excalidraw/Mermaid) with an inert proxy in
3562
3567
  // the server bundle. Without this, Nitro's Rolldown build pulls the real
3563
3568
  // Excalidraw into a shared vendor chunk imported statically by the SSR render
@@ -17,11 +17,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
17
17
  id?: undefined;
18
18
  provider?: undefined;
19
19
  } | {
20
+ error?: undefined;
20
21
  configured?: undefined;
21
22
  connectPath?: undefined;
22
23
  url: string;
23
24
  id: string;
24
25
  provider: string;
25
- error?: undefined;
26
26
  }>;
27
27
  export default _default;
@@ -28,6 +28,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
28
28
  } | {
29
29
  count?: undefined;
30
30
  updated?: undefined;
31
- ok: boolean;
32
31
  error?: undefined;
32
+ ok: boolean;
33
33
  }>>;
@@ -62,6 +62,6 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
62
62
  summary?: undefined;
63
63
  spans?: undefined;
64
64
  id?: undefined;
65
- ok: boolean;
66
65
  error?: undefined;
66
+ ok: boolean;
67
67
  }>>;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- error: string;
52
51
  ok?: undefined;
52
+ error: string;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -328,6 +328,40 @@ export interface RunBuilderAgentResult {
328
328
  url: string;
329
329
  status: string;
330
330
  }
331
+ export interface BuilderProjectLookupArgs {
332
+ repoUrl: string;
333
+ }
334
+ export interface BuilderProjectResult {
335
+ projectId: string;
336
+ name: string;
337
+ repoUrl: string;
338
+ browserUrl: string;
339
+ created: boolean;
340
+ }
341
+ /**
342
+ * Find an existing Builder project connected to a repository. Dispatch uses
343
+ * this before provisioning so a first app request cannot create a duplicate
344
+ * workspace project when the project id has not been saved yet.
345
+ */
346
+ export declare function findBuilderProjectForRepo(args: BuilderProjectLookupArgs): Promise<BuilderProjectResult | null>;
347
+ /**
348
+ * Create a Builder project connected to a repository through the public
349
+ * projects API. This is the server-side bridge used by Dispatch; online
350
+ * Claude and ChatGPT hosts do not need a separate Builder CMS MCP connector.
351
+ */
352
+ export declare function createBuilderProject(args: {
353
+ name: string;
354
+ repoUrl: string;
355
+ }): Promise<BuilderProjectResult>;
356
+ /**
357
+ * Reuse a connected Builder project or create it once when Dispatch is first
358
+ * used for a workspace. The lookup and create calls intentionally stay in
359
+ * this shared server helper so all callers use the same authenticated path.
360
+ */
361
+ export declare function ensureBuilderProject(args: {
362
+ name: string;
363
+ repoUrl: string;
364
+ }): Promise<BuilderProjectResult>;
331
365
  /**
332
366
  * POST a prompt to the Builder agents-run API. The Builder agent runs in a
333
367
  * cloud sandbox and writes code to a branch; the returned URL opens that
@@ -1283,6 +1283,185 @@ function normalizeBuilderApiString(value, fieldName) {
1283
1283
  }
1284
1284
  return trimmed;
1285
1285
  }
1286
+ function normalizeBuilderProjectString(value, fieldName) {
1287
+ if (typeof value !== "string" || !value.trim()) {
1288
+ throw new Error(`Builder project response returned a blank ${fieldName}`);
1289
+ }
1290
+ const trimmed = value.trim();
1291
+ if (/[\u0000-\u001f\u007f]/.test(trimmed)) {
1292
+ throw new Error(`Builder project response returned a malformed ${fieldName}`);
1293
+ }
1294
+ return trimmed;
1295
+ }
1296
+ function normalizeBuilderRepoUrl(value) {
1297
+ const trimmed = value.trim();
1298
+ let parsed;
1299
+ try {
1300
+ parsed = new URL(trimmed);
1301
+ }
1302
+ catch {
1303
+ throw new Error("Builder project repository URL is malformed");
1304
+ }
1305
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
1306
+ throw new Error("Builder project repository URL must use HTTP or HTTPS");
1307
+ }
1308
+ return trimmed;
1309
+ }
1310
+ function comparableBuilderRepoUrl(value) {
1311
+ try {
1312
+ const parsed = new URL(value);
1313
+ const pathname = parsed.pathname.replace(/\/+$/, "").replace(/\.git$/, "");
1314
+ return `${parsed.hostname.toLowerCase()}${pathname.toLowerCase()}`;
1315
+ }
1316
+ catch {
1317
+ return value
1318
+ .trim()
1319
+ .replace(/\/+$/, "")
1320
+ .replace(/\.git$/, "")
1321
+ .toLowerCase();
1322
+ }
1323
+ }
1324
+ function builderProjectBrowserUrl(projectId) {
1325
+ return `${getBuilderAppHost().replace(/\/$/, "")}/app/projects/${encodeURIComponent(projectId)}`;
1326
+ }
1327
+ function builderProjectFromRecord(value, fallbackRepoUrl, created) {
1328
+ if (!value || typeof value !== "object" || Array.isArray(value))
1329
+ return null;
1330
+ const record = value;
1331
+ const projectId = typeof record.id === "string" && record.id.trim() ? record.id.trim() : null;
1332
+ if (!projectId)
1333
+ return null;
1334
+ const name = typeof record.name === "string" && record.name.trim()
1335
+ ? record.name.trim()
1336
+ : "Agent-Native Workspace";
1337
+ const repoUrl = typeof record.repoUrl === "string" && record.repoUrl.trim()
1338
+ ? record.repoUrl.trim()
1339
+ : fallbackRepoUrl;
1340
+ if (!repoUrl)
1341
+ return null;
1342
+ return {
1343
+ projectId: normalizeBuilderProjectString(projectId, "project id"),
1344
+ name: normalizeBuilderProjectString(name, "project name"),
1345
+ repoUrl: normalizeBuilderRepoUrl(repoUrl),
1346
+ browserUrl: builderProjectBrowserUrl(projectId),
1347
+ created,
1348
+ };
1349
+ }
1350
+ async function resolveBuilderApiCredentials() {
1351
+ const { resolveBuilderCredentials } = await import("./credential-provider.js");
1352
+ const creds = await resolveBuilderCredentials();
1353
+ if (!creds.privateKey || !creds.publicKey) {
1354
+ throw new Error("Builder keys are not configured");
1355
+ }
1356
+ return {
1357
+ ...creds,
1358
+ privateKey: creds.privateKey,
1359
+ publicKey: creds.publicKey,
1360
+ };
1361
+ }
1362
+ async function readBuilderApiObject(response, operation) {
1363
+ let parsed;
1364
+ try {
1365
+ parsed = await response.json();
1366
+ }
1367
+ catch (error) {
1368
+ throw new Error("Builder " +
1369
+ operation +
1370
+ " returned an invalid JSON response (" +
1371
+ response.status +
1372
+ ")", { cause: error });
1373
+ }
1374
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1375
+ throw new Error("Builder " +
1376
+ operation +
1377
+ " returned an invalid JSON response (" +
1378
+ response.status +
1379
+ ")");
1380
+ }
1381
+ return parsed;
1382
+ }
1383
+ function builderApiErrorMessage(parsed, fallback) {
1384
+ if (typeof parsed.error === "string" && parsed.error.trim()) {
1385
+ return parsed.error.trim();
1386
+ }
1387
+ if (typeof parsed.message === "string" && parsed.message.trim()) {
1388
+ return parsed.message.trim();
1389
+ }
1390
+ return fallback;
1391
+ }
1392
+ /**
1393
+ * Find an existing Builder project connected to a repository. Dispatch uses
1394
+ * this before provisioning so a first app request cannot create a duplicate
1395
+ * workspace project when the project id has not been saved yet.
1396
+ */
1397
+ export async function findBuilderProjectForRepo(args) {
1398
+ const repoUrl = normalizeBuilderRepoUrl(args.repoUrl);
1399
+ const creds = await resolveBuilderApiCredentials();
1400
+ const url = new URL("/projects", getBuilderApiHost());
1401
+ url.searchParams.set("apiKey", creds.publicKey);
1402
+ url.searchParams.set("includeHidden", "true");
1403
+ const response = await fetch(url, {
1404
+ method: "GET",
1405
+ headers: { Authorization: `Bearer ${creds.privateKey}` },
1406
+ });
1407
+ const parsed = await readBuilderApiObject(response, "project lookup");
1408
+ if (!response.ok) {
1409
+ throw new Error(builderApiErrorMessage(parsed, `Builder project lookup failed (${response.status})`));
1410
+ }
1411
+ if (!Array.isArray(parsed.projects)) {
1412
+ throw new Error("Builder project lookup returned no projects list");
1413
+ }
1414
+ const comparableRepoUrl = comparableBuilderRepoUrl(repoUrl);
1415
+ for (const project of parsed.projects) {
1416
+ const normalized = builderProjectFromRecord(project, null, false);
1417
+ if (normalized &&
1418
+ comparableBuilderRepoUrl(normalized.repoUrl) === comparableRepoUrl) {
1419
+ return normalized;
1420
+ }
1421
+ }
1422
+ return null;
1423
+ }
1424
+ /**
1425
+ * Create a Builder project connected to a repository through the public
1426
+ * projects API. This is the server-side bridge used by Dispatch; online
1427
+ * Claude and ChatGPT hosts do not need a separate Builder CMS MCP connector.
1428
+ */
1429
+ export async function createBuilderProject(args) {
1430
+ const name = normalizeBuilderProjectString(args.name, "project name");
1431
+ const repoUrl = normalizeBuilderRepoUrl(args.repoUrl);
1432
+ const creds = await resolveBuilderApiCredentials();
1433
+ const url = new URL("/projects/create", getBuilderApiHost());
1434
+ url.searchParams.set("apiKey", creds.publicKey);
1435
+ const response = await fetch(url, {
1436
+ method: "POST",
1437
+ headers: {
1438
+ Authorization: `Bearer ${creds.privateKey}`,
1439
+ "Content-Type": "application/json",
1440
+ },
1441
+ body: JSON.stringify({
1442
+ source: { kind: "repo", repoUrl },
1443
+ name,
1444
+ }),
1445
+ });
1446
+ const parsed = await readBuilderApiObject(response, "project creation");
1447
+ if (!response.ok) {
1448
+ throw new Error(builderApiErrorMessage(parsed, `Builder project creation failed (${response.status})`));
1449
+ }
1450
+ const project = builderProjectFromRecord(parsed.project, repoUrl, true);
1451
+ if (!project) {
1452
+ throw new Error("Builder project creation returned no project id");
1453
+ }
1454
+ return project;
1455
+ }
1456
+ /**
1457
+ * Reuse a connected Builder project or create it once when Dispatch is first
1458
+ * used for a workspace. The lookup and create calls intentionally stay in
1459
+ * this shared server helper so all callers use the same authenticated path.
1460
+ */
1461
+ export async function ensureBuilderProject(args) {
1462
+ const existing = await findBuilderProjectForRepo({ repoUrl: args.repoUrl });
1463
+ return existing ?? createBuilderProject(args);
1464
+ }
1286
1465
  function normalizeBuilderBranchUrl(value) {
1287
1466
  const urlString = normalizeBuilderApiString(value, "url");
1288
1467
  let parsed;
@@ -288,6 +288,11 @@ interface LegacyCoreRouteInitSettings {
288
288
  }
289
289
  type CoreRouteSettingReader = (key: string) => Promise<Record<string, unknown> | null>;
290
290
  export declare function readLegacyCoreRouteInitSettings(readSetting?: CoreRouteSettingReader): Promise<LegacyCoreRouteInitSettings>;
291
+ /**
292
+ * Production release jobs own schema setup. Request functions must not spend
293
+ * their cold-start budget on legacy cleanup or best-effort table warmups.
294
+ */
295
+ export declare function shouldRunCoreRouteBootDatabaseWork(env?: NodeJS.ProcessEnv): boolean;
291
296
  export declare function createCoreRoutesPlugin(options?: CoreRoutesPluginOptions): NitroPluginDef;
292
297
  /**
293
298
  * Default core routes plugin — mount with no configuration needed.
@@ -8,7 +8,7 @@ import { canUpdateAgentLoopSettings, readAgentLoopSettings, resetAgentLoopSettin
8
8
  import { getState, putState, deleteState, listComposeDrafts, getComposeDraft, putComposeDraft, deleteComposeDraft, deleteAllComposeDrafts, getStateMany, } from "../application-state/handlers.js";
9
9
  import { mountBrowserSessionRoutes } from "../browser-sessions/routes.js";
10
10
  import { mountDbAdminRoutes } from "../db-admin/routes.js";
11
- import { getDbExec } from "../db/client.js";
11
+ import { getDbExec, isProductionServerlessFunctionRuntime, } from "../db/client.js";
12
12
  import { getDatabaseRuntimeFingerprint, getRuntimeDebugFingerprint, runDatabaseSchemaHealthCheck, } from "../db/runtime-diagnostics.js";
13
13
  import { ssrfSafeFetch } from "../extensions/url-safety.js";
14
14
  import { uploadFile, getActiveFileUploadProviderForRequest, listFileUploadProviders, } from "../file-upload/index.js";
@@ -814,6 +814,13 @@ export async function readLegacyCoreRouteInitSettings(readSetting = getSetting)
814
814
  builderDisconnected: builderDisconnected,
815
815
  };
816
816
  }
817
+ /**
818
+ * Production release jobs own schema setup. Request functions must not spend
819
+ * their cold-start budget on legacy cleanup or best-effort table warmups.
820
+ */
821
+ export function shouldRunCoreRouteBootDatabaseWork(env = process.env) {
822
+ return !isProductionServerlessFunctionRuntime(env);
823
+ }
817
824
  /**
818
825
  * Creates a Nitro plugin that mounts all standard agent-native framework routes.
819
826
  *
@@ -913,7 +920,10 @@ export function createCoreRoutesPlugin(options = {}) {
913
920
  return EMPTY_SPECULATION_RULES;
914
921
  }));
915
922
  await awaitBootstrap(nitroApp);
916
- const { persistedEnvVars, builderDisconnected } = await readLegacyCoreRouteInitSettings();
923
+ const runBootDatabaseWork = shouldRunCoreRouteBootDatabaseWork();
924
+ const { persistedEnvVars, builderDisconnected } = runBootDatabaseWork
925
+ ? await readLegacyCoreRouteInitSettings()
926
+ : { persistedEnvVars: null, builderDisconnected: null };
917
927
  // Legacy cleanup: key saves now go to scoped app_secrets rows. Do not
918
928
  // rehydrate the old deployment-global `persisted-env-vars` row into
919
929
  // process.env; keep only the Builder scrub so stale leaked keys self-heal.
@@ -996,7 +1006,8 @@ export function createCoreRoutesPlugin(options = {}) {
996
1006
  try {
997
1007
  const { createObservabilityHandler } = await import("../observability/routes.js");
998
1008
  const { ensureObservabilityTables } = await import("../observability/store.js");
999
- ensureObservabilityTables().catch(() => { });
1009
+ if (runBootDatabaseWork)
1010
+ ensureObservabilityTables().catch(() => { });
1000
1011
  getH3App(nitroApp).use(`${FRAMEWORK_ROUTE_PREFIX}/observability`, createObservabilityHandler());
1001
1012
  }
1002
1013
  catch {
@@ -1009,8 +1020,10 @@ export function createCoreRoutesPlugin(options = {}) {
1009
1020
  try {
1010
1021
  const { ensureAuditTables } = await import("../audit/store.js");
1011
1022
  const { startAuditCleanupJob } = await import("../audit/cleanup-job.js");
1012
- ensureAuditTables().catch(() => { });
1013
- startAuditCleanupJob();
1023
+ if (runBootDatabaseWork) {
1024
+ ensureAuditTables().catch(() => { });
1025
+ startAuditCleanupJob();
1026
+ }
1014
1027
  }
1015
1028
  catch {
1016
1029
  // Audit module not available — skip
@@ -2880,7 +2893,8 @@ export function createCoreRoutesPlugin(options = {}) {
2880
2893
  try {
2881
2894
  const { ensureExtensionsTables, registerExtensionsShareable } = await import("../extensions/store.js");
2882
2895
  const { createExtensionsHandler } = await import("../extensions/routes.js");
2883
- ensureExtensionsTables().catch(() => { });
2896
+ if (runBootDatabaseWork)
2897
+ ensureExtensionsTables().catch(() => { });
2884
2898
  registerExtensionsShareable();
2885
2899
  const extensionsHandler = createExtensionsHandler({
2886
2900
  extensionTools: options.extensionTools,
@@ -2893,7 +2907,8 @@ export function createCoreRoutesPlugin(options = {}) {
2893
2907
  // Extension-point slots — sub-system of extensions.
2894
2908
  const { ensureSlotTables } = await import("../extensions/slots/store.js");
2895
2909
  const { createSlotsHandler } = await import("../extensions/slots/routes.js");
2896
- ensureSlotTables().catch(() => { });
2910
+ if (runBootDatabaseWork)
2911
+ ensureSlotTables().catch(() => { });
2897
2912
  getH3App(nitroApp).use(`${P}/slots`, createSlotsHandler());
2898
2913
  }
2899
2914
  catch {
@@ -2902,7 +2917,8 @@ export function createCoreRoutesPlugin(options = {}) {
2902
2917
  // ─── Data programs (stored server-side JS scripts + run cache) ─────
2903
2918
  try {
2904
2919
  const { ensureDataProgramTables, registerDataProgramsShareable } = await import("../data-programs/store.js");
2905
- ensureDataProgramTables().catch(() => { });
2920
+ if (runBootDatabaseWork)
2921
+ ensureDataProgramTables().catch(() => { });
2906
2922
  registerDataProgramsShareable();
2907
2923
  }
2908
2924
  catch {
@@ -70,7 +70,7 @@ export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, resolveOAut
70
70
  export { buildWorkspaceProviderAuthorizationUrl, createWorkspaceProviderOAuthHandler, exchangeWorkspaceProviderOAuthCode, handleWorkspaceProviderOAuthCallback, handleWorkspaceProviderOAuthStart, isWorkspaceProviderOAuthFlowValid, mergeWorkspaceOAuthValues, resolveWorkspaceProviderIdentity, workspaceProviderOAuthPath, type GenericWorkspaceOAuthProvider, type WorkspaceProviderOAuthFlow, } from "./workspace-provider-oauth.js";
71
71
  export { FeatureNotConfiguredError, hasBuilderPrivateKey, isBuilderEnvManaged, getBuilderProxyOrigin, getBuilderImageGenerationBaseUrl, getBuilderWebSearchBaseUrl, getBuilderAuthHeader, resolveBuilderPrivateKey, resolveBuilderAuthHeader, resolveHasBuilderPrivateKey, resolveHasCompleteBuilderConnection, resolveBuilderCredentials, resolveBuilderCredentialsDetailed, resolveBuilderCredentialSource, resolveBuilderCredential, readDeployCredentialEnv, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, type BuilderCredentialsDetailed, } from "./credential-provider.js";
72
72
  export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, type BuildBuilderDesignSystemIndexFilesOptions, type BuilderDesignSystemCodeFileInput, type BuilderDesignSystemDecodeJobStatus, type BuilderDesignSystemDocsOptions, type BuilderDesignSystemDocument, type BuilderDesignSystemHydratedReference, type BuilderDesignSystemIndexFile, type BuilderDesignSystemIndexFromSourcesOptions, type BuilderDesignSystemIndexOptions, type BuilderDesignSystemIndexResult, type BuilderDesignSystemUploadAttachment, type BuilderDesignSystemUploadSlot, type BuilderDesignSystemProxyFields, type BuilderDesignSystemProxyFieldsOptions, type BuilderDesignSystemProxyReference, type BuilderDesignSystemSourceKind, } from "./builder-design-systems.js";
73
- export { getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, type RunBuilderAgentResult, } from "./builder-browser.js";
73
+ export { createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, type BuilderProjectResult, type RunBuilderAgentResult, } from "./builder-browser.js";
74
74
  export { ensureFusionContainer, sendFusionBranchMessage, pushFusionBranch, reserveFusionHostingSlug, deployFusionProject, getFusionDeploys, getFusionBranchEditorUrl, getFusionHostingUrl, type FusionBranchRef, type EnsureFusionContainerResult, type SendFusionMessageResult, } from "./fusion-app.js";
75
75
  export { sendEmail, isEmailConfigured, getEmailReadiness, getEmailProvider, type EmailAttachment, type EmailReadiness, type EmailProvider, type SendEmailArgs, } from "./email.js";
76
76
  export { defineTransactionalEmail, listTransactionalEmails, getTransactionalEmail, renderTransactionalEmailPreview, type TransactionalEmailDefinition, type RegisteredTransactionalEmail, } from "../email-catalog/registry.js";
@@ -75,7 +75,7 @@ export { isElectron, isMobile, getOrigin, getAppBasePath, getAppUrl, resolveOAut
75
75
  export { buildWorkspaceProviderAuthorizationUrl, createWorkspaceProviderOAuthHandler, exchangeWorkspaceProviderOAuthCode, handleWorkspaceProviderOAuthCallback, handleWorkspaceProviderOAuthStart, isWorkspaceProviderOAuthFlowValid, mergeWorkspaceOAuthValues, resolveWorkspaceProviderIdentity, workspaceProviderOAuthPath, } from "./workspace-provider-oauth.js";
76
76
  export { FeatureNotConfiguredError, hasBuilderPrivateKey, isBuilderEnvManaged, getBuilderProxyOrigin, getBuilderImageGenerationBaseUrl, getBuilderWebSearchBaseUrl, getBuilderAuthHeader, resolveBuilderPrivateKey, resolveBuilderAuthHeader, resolveHasBuilderPrivateKey, resolveHasCompleteBuilderConnection, resolveBuilderCredentials, resolveBuilderCredentialsDetailed, resolveBuilderCredentialSource, resolveBuilderCredential, readDeployCredentialEnv, writeBuilderCredentials, deleteBuilderCredentials, resolveSecret, } from "./credential-provider.js";
77
77
  export { builderDesignSystemUrl, builderProjectBranchUrl, buildBuilderDesignSystemIndexFiles, createBuilderDesignSystemProxyFields, fetchBuilderDesignSystemDecodeJobStatus, fetchBuilderDesignSystemDocs, getBuilderDesignSystemsBaseUrl, hydrateBuilderDesignSystemReference, indexBuilderDesignSystem, localBuilderDesignSystemId, mimeTypeForBuilderDesignSystemFilename, parseBuilderDesignSystemProxyReference, startBuilderDesignSystemIndex, startBuilderDesignSystemUpload, } from "./builder-design-systems.js";
78
- export { getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, } from "./builder-browser.js";
78
+ export { createBuilderProject, ensureBuilderProject, findBuilderProjectForRepo, getBuilderBranchProjectId, isBuilderBranchingEnabled, requestBuilderBrowserConnection, resolveBuilderBranchProjectId, resolveIsBuilderBranchingEnabled, runBuilderAgent, } from "./builder-browser.js";
79
79
  export { ensureFusionContainer, sendFusionBranchMessage, pushFusionBranch, reserveFusionHostingSlug, deployFusionProject, getFusionDeploys, getFusionBranchEditorUrl, getFusionHostingUrl, } from "./fusion-app.js";
80
80
  export { sendEmail, isEmailConfigured, getEmailReadiness, getEmailProvider, } from "./email.js";
81
81
  export { defineTransactionalEmail, listTransactionalEmails, getTransactionalEmail, renderTransactionalEmailPreview, } from "../email-catalog/registry.js";
@@ -1,11 +1,11 @@
1
1
  export declare const DEFAULT_PUBLIC_CACHE_CONTROL = "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
2
2
  export declare const DEFAULT_SSR_CACHE_CONTROL = "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
3
3
  export declare const DEFAULT_SSR_CDN_CACHE_CONTROL = "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
4
- export declare const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = "public, durable, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
4
+ export declare const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = "public, durable, s-maxage=31536000, stale-while-revalidate=604800, stale-if-error=3600";
5
5
  export declare const DEFAULT_SSR_CACHE_HEADERS: {
6
6
  readonly "cache-control": "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
7
7
  readonly "cdn-cache-control": "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
8
- readonly "netlify-cdn-cache-control": "public, durable, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
8
+ readonly "netlify-cdn-cache-control": "public, durable, s-maxage=31536000, stale-while-revalidate=604800, stale-if-error=3600";
9
9
  };
10
10
  /**
11
11
  * Deployment-wide override for the SSR shell cache policy.
@@ -1,7 +1,7 @@
1
1
  export const DEFAULT_PUBLIC_CACHE_CONTROL = "public, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
2
2
  export const DEFAULT_SSR_CACHE_CONTROL = DEFAULT_PUBLIC_CACHE_CONTROL;
3
3
  export const DEFAULT_SSR_CDN_CACHE_CONTROL = DEFAULT_SSR_CACHE_CONTROL;
4
- export const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = "public, durable, max-age=600, stale-while-revalidate=604800, stale-if-error=3600";
4
+ export const DEFAULT_SSR_NETLIFY_CDN_CACHE_CONTROL = "public, durable, s-maxage=31536000, stale-while-revalidate=604800, stale-if-error=3600";
5
5
  export const DEFAULT_SSR_CACHE_HEADERS = {
6
6
  "cache-control": DEFAULT_SSR_CACHE_CONTROL,
7
7
  "cdn-cache-control": DEFAULT_SSR_CDN_CACHE_CONTROL,
@@ -85,7 +85,7 @@ export function ssrCacheHeadersForPolicy(policy) {
85
85
  // the 7-day default SWR here would hand back the staleness they opted out of.
86
86
  const control = `public, max-age=${policy.seconds}, ` +
87
87
  `stale-while-revalidate=${policy.seconds}, stale-if-error=3600`;
88
- const netlifyControl = `public, durable, max-age=${policy.seconds}, ` +
88
+ const netlifyControl = `public, durable, s-maxage=${policy.seconds}, ` +
89
89
  `stale-while-revalidate=${policy.seconds}, stale-if-error=3600`;
90
90
  return {
91
91
  "cache-control": control,
@@ -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