@agent-native/core 0.146.7 → 0.147.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -6
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  4. package/corpus/templates/analytics/DEVELOPING.md +59 -0
  5. package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
  6. package/corpus/templates/analytics/package.json +1 -0
  7. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +889 -0
  8. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +70 -0
  9. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +117 -12
  10. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -6
  11. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  12. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +9 -0
  13. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -6
  14. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  15. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -6
  16. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  17. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  18. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  19. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  20. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -6
  21. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  22. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +16 -4
  23. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +14 -5
  24. package/corpus/templates/clips/package.json +1 -0
  25. package/corpus/templates/clips/react-router.config.ts +7 -0
  26. package/corpus/templates/clips/server/plugins/auth.ts +6 -1
  27. package/corpus/templates/clips/shared/prerendered-public-paths.ts +21 -0
  28. package/corpus/templates/clips/shared/share-meta.ts +8 -3
  29. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -6
  30. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  31. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -6
  32. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  33. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -6
  34. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  35. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -6
  36. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  37. package/corpus/templates/dispatch/app/chat-first-pages.ts +747 -0
  38. package/corpus/templates/dispatch/app/i18n-data.ts +181 -0
  39. package/corpus/templates/dispatch/app/routes/settings.tsx +62 -1
  40. package/corpus/templates/dispatch/changelog/2026-08-08-chat-first-navigation-keeps-conversations-central-while-open.md +6 -0
  41. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +9 -0
  42. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -6
  43. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  44. package/corpus/templates/factory/actions/run-factory-automation.ts +1 -0
  45. package/corpus/templates/factory/app/routes/factory.tsx +108 -76
  46. package/corpus/templates/factory/changelog/2026-08-08-scheduler-health-moves-to-settings.md +6 -0
  47. package/corpus/templates/factory/netlify.toml +1 -1
  48. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -6
  49. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  50. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -6
  51. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  52. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -6
  53. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  54. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +9 -0
  55. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -6
  56. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  57. package/corpus/templates/plan/app/lib/plan-document-title.ts +3 -1
  58. package/corpus/templates/plan/app/root.tsx +1 -0
  59. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -6
  60. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  61. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +9 -0
  62. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -6
  63. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  64. package/dist/agent/engine/builder-engine.d.ts +11 -1
  65. package/dist/agent/engine/builder-engine.js +11 -4
  66. package/dist/chat-threads/store.d.ts +2 -0
  67. package/dist/chat-threads/store.js +1 -1
  68. package/dist/cli/agent-plugin.d.ts +5 -2
  69. package/dist/cli/agent-plugin.js +17 -9
  70. package/dist/cli/code-agent-executor.js +25 -5
  71. package/dist/cli/code-agent-mcp-config.d.ts +21 -0
  72. package/dist/cli/code-agent-mcp-config.js +103 -0
  73. package/dist/client/NewWorkspaceAppFlow.js +4 -1
  74. package/dist/client/agent-chat/index.d.ts +4 -1
  75. package/dist/client/agent-chat/index.js +4 -1
  76. package/dist/client/agent-page/AgentTabsPage.d.ts +1 -0
  77. package/dist/client/agent-page/AgentTabsPage.js +4 -3
  78. package/dist/client/app-providers.d.ts +3 -1
  79. package/dist/client/app-providers.js +50 -5
  80. package/dist/client/chat/runtime.js +63 -0
  81. package/dist/client/chat-first/agents-pane.d.ts +2 -0
  82. package/dist/client/chat-first/agents-pane.js +6 -0
  83. package/dist/client/chat-first/app-pane.d.ts +2 -0
  84. package/dist/client/chat-first/app-pane.js +6 -0
  85. package/dist/client/chat-first/apps-rail.d.ts +2 -0
  86. package/dist/client/chat-first/apps-rail.js +103 -0
  87. package/dist/client/chat-first/browser-pane.d.ts +2 -0
  88. package/dist/client/chat-first/browser-pane.js +64 -0
  89. package/dist/client/chat-first/chat-history.d.ts +12 -0
  90. package/dist/client/chat-first/chat-history.js +10 -0
  91. package/dist/client/chat-first/copy.d.ts +2 -0
  92. package/dist/client/chat-first/copy.js +117 -0
  93. package/dist/client/chat-first/index.d.ts +13 -0
  94. package/dist/client/chat-first/index.js +12 -0
  95. package/dist/client/chat-first/primary-nav.d.ts +8 -0
  96. package/dist/client/chat-first/primary-nav.js +6 -0
  97. package/dist/client/chat-first/session-watch-pane.d.ts +2 -0
  98. package/dist/client/chat-first/session-watch-pane.js +9 -0
  99. package/dist/client/chat-first/surface-panel.d.ts +9 -0
  100. package/dist/client/chat-first/surface-panel.js +9 -0
  101. package/dist/client/chat-first/surface-tabs.d.ts +9 -0
  102. package/dist/client/chat-first/surface-tabs.js +74 -0
  103. package/dist/client/chat-first/types.d.ts +74 -0
  104. package/dist/client/chat-first/types.js +1 -0
  105. package/dist/client/chat-first-agent-activity.d.ts +11 -0
  106. package/dist/client/chat-first-agent-activity.js +51 -0
  107. package/dist/client/chat-first-surface-panel-toggle.d.ts +5 -0
  108. package/dist/client/chat-first-surface-panel-toggle.js +6 -0
  109. package/dist/client/chat-first.d.ts +208 -0
  110. package/dist/client/chat-first.js +816 -0
  111. package/dist/client/extensions/ExtensionViewer.js +8 -1
  112. package/dist/client/resources/McpIntegrationDialog.js +3 -2
  113. package/dist/client/resources/McpServerDetail.js +6 -11
  114. package/dist/client/resources/index.d.ts +1 -0
  115. package/dist/client/resources/index.js +1 -0
  116. package/dist/client/resources/use-mcp-servers.d.ts +20 -0
  117. package/dist/client/resources/use-mcp-servers.js +82 -46
  118. package/dist/client/settings/index.d.ts +1 -0
  119. package/dist/client/settings/index.js +1 -0
  120. package/dist/collab/awareness.d.ts +2 -2
  121. package/dist/collab/routes.d.ts +1 -1
  122. package/dist/jobs/background-automation-runner.js +19 -2
  123. package/dist/jobs/scheduler-health.d.ts +20 -0
  124. package/dist/jobs/scheduler-health.js +86 -1
  125. package/dist/jobs/scheduler.js +38 -1
  126. package/dist/mcp-client/routes.d.ts +3 -0
  127. package/dist/mcp-client/routes.js +14 -0
  128. package/dist/notifications/routes.d.ts +1 -1
  129. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  130. package/dist/server/agents-bundle.d.ts +2 -0
  131. package/dist/server/agents-bundle.js +31 -2
  132. package/dist/server/credential-provider.d.ts +8 -2
  133. package/dist/server/credential-provider.js +13 -9
  134. package/dist/shared/chat-first-app-creation.d.ts +19 -0
  135. package/dist/shared/chat-first-app-creation.js +75 -0
  136. package/dist/shared/document-title.d.ts +7 -0
  137. package/dist/shared/document-title.js +29 -0
  138. package/dist/shared/index.d.ts +2 -0
  139. package/dist/shared/index.js +2 -0
  140. package/dist/styles/chat-history-list.css +16 -0
  141. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  142. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  143. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  144. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  145. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  146. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  147. package/dist/templates/default/react-router.config.ts +18 -0
  148. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  149. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  150. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  151. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  152. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  153. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
  154. package/package.json +4 -3
  155. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  156. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  157. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  158. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  159. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  160. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  161. package/src/templates/default/react-router.config.ts +18 -0
  162. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  163. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  164. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  165. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  166. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  167. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
@@ -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
  }>>;
@@ -311,8 +311,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
311
311
  notes?: string | undefined;
312
312
  scope?: "org" | "user" | undefined;
313
313
  }, {
314
- message?: undefined;
315
314
  id?: undefined;
315
+ message?: undefined;
316
316
  provider?: undefined;
317
317
  deleted?: undefined;
318
318
  providers: {
@@ -329,9 +329,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
329
329
  registered?: undefined;
330
330
  label?: undefined;
331
331
  } | {
332
+ id?: undefined;
332
333
  message?: undefined;
333
334
  count?: undefined;
334
- id?: undefined;
335
335
  deleted?: undefined;
336
336
  providers?: undefined;
337
337
  found: boolean;
@@ -96,6 +96,8 @@ export interface AgentsBundle {
96
96
  }
97
97
  export interface AgentsBundleReadOptions {
98
98
  instructions?: AgentNativeInstructionsConfig;
99
+ /** Additional skill roots supplied by a local host, such as installed plugins. */
100
+ additionalSkillDirs?: string[];
99
101
  }
100
102
  export interface AgentInstructionPaths {
101
103
  runtime: string;
@@ -230,6 +230,27 @@ function readSkillsDir(skillsDir, rootForRelative, out, skipExistingNames) {
230
230
  }
231
231
  }
232
232
  }
233
+ function readNestedSkillsDir(skillsDir, rootForRelative, out) {
234
+ if (!fs.existsSync(skillsDir))
235
+ return;
236
+ readSkillsDir(skillsDir, rootForRelative, out, true);
237
+ let entries;
238
+ try {
239
+ entries = fs.readdirSync(skillsDir, { withFileTypes: true });
240
+ }
241
+ catch {
242
+ return;
243
+ }
244
+ for (const entry of entries) {
245
+ if (!entry.isDirectory() || entry.name === "." || entry.name === "..") {
246
+ continue;
247
+ }
248
+ const nestedDir = path.join(skillsDir, entry.name);
249
+ if (fs.existsSync(path.join(nestedDir, "SKILL.md")))
250
+ continue;
251
+ readSkillsDir(nestedDir, rootForRelative, out, true);
252
+ }
253
+ }
233
254
  /**
234
255
  * Read AGENTS.md + all skills directly from the filesystem rooted at `cwd`.
235
256
  * Optionally also reads a workspace-core's AGENTS.md and skills directory
@@ -256,9 +277,9 @@ export function readAgentsBundleFromFs(cwd, workspaceSource = null, options = {}
256
277
  // overwrite the template's. `.agents/skills` is canonical; `.agent/skills`
257
278
  // is accepted as a legacy alias and does not override canonical skills.
258
279
  const skills = {};
259
- for (const [index, relSkillsDir] of TEMPLATE_SKILLS_DIRS.entries()) {
280
+ for (const relSkillsDir of TEMPLATE_SKILLS_DIRS) {
260
281
  try {
261
- readSkillsDir(path.join(cwd, relSkillsDir), cwd, skills, index > 0);
282
+ readNestedSkillsDir(path.join(cwd, relSkillsDir), cwd, skills);
262
283
  }
263
284
  catch { }
264
285
  }
@@ -268,6 +289,14 @@ export function readAgentsBundleFromFs(cwd, workspaceSource = null, options = {}
268
289
  }
269
290
  catch { }
270
291
  }
292
+ for (const skillsDir of options.additionalSkillDirs ?? []) {
293
+ try {
294
+ readNestedSkillsDir(skillsDir, cwd, skills);
295
+ }
296
+ catch {
297
+ // Optional host-provided skills must not make the coding session fail.
298
+ }
299
+ }
271
300
  return {
272
301
  // Keep the old field useful for callers that only know about the runtime
273
302
  // bundle. Audience-aware consumers should use the explicit fields.
@@ -85,6 +85,12 @@ export declare function isDeployCredentialFallbackAllowed(): boolean;
85
85
  export declare function canUseDeployCredentialFallbackForRequest(key?: string): boolean;
86
86
  type BuilderCredentialSource = "user" | "org" | "workspace" | "env";
87
87
  export declare function isBuilderPrivateKey(value: string | null | undefined): boolean;
88
+ export interface BuilderCredentialLookupIdentity {
89
+ /** The verified owner of a background run, when it has no browser request. */
90
+ userEmail?: string | null;
91
+ /** The verified organization attached to that run, when one exists. */
92
+ orgId?: string | null;
93
+ }
88
94
  /**
89
95
  * Resolve a Builder credential for the current request. User/org credentials
90
96
  * win; deployment env is only a fallback. This lets local/root .env keys keep
@@ -153,13 +159,13 @@ export interface BuilderCredentialsDetailed {
153
159
  * Callers that only need the plain credential bundle (the historical shape)
154
160
  * should use `resolveBuilderCredentials()` instead.
155
161
  */
156
- export declare function resolveBuilderCredentialsDetailed(): Promise<BuilderCredentialsDetailed>;
162
+ export declare function resolveBuilderCredentialsDetailed(identity?: BuilderCredentialLookupIdentity): Promise<BuilderCredentialsDetailed>;
157
163
  /**
158
164
  * Resolve the Builder assistant credential bundle from one complete scope.
159
165
  * Kept to its original return shape (no `source`/`lookupFailed`) for existing
160
166
  * callers; use `resolveBuilderCredentialsDetailed()` for those fields.
161
167
  */
162
- export declare function resolveBuilderCredentials(): Promise<{
168
+ export declare function resolveBuilderCredentials(identity?: BuilderCredentialLookupIdentity): Promise<{
163
169
  privateKey: string | null;
164
170
  publicKey: string | null;
165
171
  userId: string | null;
@@ -444,8 +444,8 @@ async function resolveScopedBuilderCredential(key) {
444
444
  cause: orgLookupCause,
445
445
  };
446
446
  }
447
- async function resolveScopedBuilderCredentials() {
448
- const email = getRequestUserEmail();
447
+ async function resolveScopedBuilderCredentials(identity) {
448
+ const email = identity?.userEmail?.trim() || getRequestUserEmail();
449
449
  if (!email)
450
450
  return { creds: null, lookupFailed: false };
451
451
  const traceLookup = shouldTraceCredentialResolve();
@@ -463,7 +463,7 @@ async function resolveScopedBuilderCredentials() {
463
463
  if (await isCompleteBuilderConnection(userCreds)) {
464
464
  return { creds: userCreds, lookupFailed: false };
465
465
  }
466
- let orgId = getRequestOrgId();
466
+ let orgId = identity?.orgId?.trim() || getRequestOrgId();
467
467
  let orgSource = orgId
468
468
  ? "request"
469
469
  : "none";
@@ -527,8 +527,12 @@ export async function resolveBuilderCredential(key) {
527
527
  const envValue = canUseBuilderDeployCredentialFallbackForRequest()
528
528
  ? (readDeployCredentialEnv(key) ?? null)
529
529
  : null;
530
- if (envValue)
530
+ if (envValue) {
531
+ // A deploy fallback is still useful, but it must not turn a transient
532
+ // credential-store failure into a clean connected result for Builder.
533
+ assertCredentialStoreReadable(scoped);
531
534
  return envValue;
535
+ }
532
536
  // Nothing answered AND the store never gave a real answer: that is not
533
537
  // "not connected", it is "we could not look".
534
538
  assertCredentialStoreReadable(scoped);
@@ -589,8 +593,8 @@ export async function resolveBuilderCredentialSource() {
589
593
  * Callers that only need the plain credential bundle (the historical shape)
590
594
  * should use `resolveBuilderCredentials()` instead.
591
595
  */
592
- export async function resolveBuilderCredentialsDetailed() {
593
- const { creds: scoped, lookupFailed, cause, } = await resolveScopedBuilderCredentials();
596
+ export async function resolveBuilderCredentialsDetailed(identity) {
597
+ const { creds: scoped, lookupFailed, cause, } = await resolveScopedBuilderCredentials(identity);
594
598
  if (scoped) {
595
599
  const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, source, } = scoped;
596
600
  return {
@@ -683,8 +687,8 @@ export async function resolveBuilderCredentialsDetailed() {
683
687
  * Kept to its original return shape (no `source`/`lookupFailed`) for existing
684
688
  * callers; use `resolveBuilderCredentialsDetailed()` for those fields.
685
689
  */
686
- export async function resolveBuilderCredentials() {
687
- const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, } = await resolveBuilderCredentialsDetailed();
690
+ export async function resolveBuilderCredentials(identity) {
691
+ const { privateKey, publicKey, userId, orgName, orgKind, subscription, subscriptionLevel, subscriptionName, isEnterprise, isFreeAccount, } = await resolveBuilderCredentialsDetailed(identity);
688
692
  return {
689
693
  privateKey,
690
694
  publicKey,
@@ -1210,7 +1214,7 @@ export async function resolveSecretDetailed(key) {
1210
1214
  }
1211
1215
  return {
1212
1216
  value: envFallback,
1213
- lookupFailed: lookupFailed && !envFallback,
1217
+ lookupFailed,
1214
1218
  cause,
1215
1219
  };
1216
1220
  }
@@ -0,0 +1,19 @@
1
+ export type ChatFirstAppCreationVaultAccessMode = "all-apps" | "manual";
2
+ export interface ChatFirstAppCreationResource {
3
+ name: string;
4
+ kind: string;
5
+ path: string;
6
+ }
7
+ export interface ChatFirstAppCreationPromptInput {
8
+ appId: string;
9
+ prompt: string;
10
+ selectedKeys: string[];
11
+ selectedResources: ChatFirstAppCreationResource[];
12
+ vaultAccessMode: ChatFirstAppCreationVaultAccessMode;
13
+ appRoot?: string;
14
+ mountPath?: string;
15
+ scaffoldCommand?: string;
16
+ additionalInstructions?: string[];
17
+ }
18
+ export declare function titleFromChatFirstAppPrompt(prompt: string): string;
19
+ export declare function buildChatFirstAppCreationPrompt(input: ChatFirstAppCreationPromptInput): string;
@@ -0,0 +1,75 @@
1
+ function slugify(value) {
2
+ return value
3
+ .toLowerCase()
4
+ .replace(/[^a-z0-9]+/g, "-")
5
+ .replace(/^-+|-+$/g, "")
6
+ .replace(/^[^a-z]+/, "")
7
+ .slice(0, 48);
8
+ }
9
+ export function titleFromChatFirstAppPrompt(prompt) {
10
+ const cleaned = prompt
11
+ .replace(/\b(build|create|make|an?|the|app|tool|dashboard)\b/gi, " ")
12
+ .replace(/\s+/g, " ")
13
+ .trim();
14
+ return slugify(cleaned || "new-app") || "new-app";
15
+ }
16
+ export function buildChatFirstAppCreationPrompt(input) {
17
+ const appRoot = input.appRoot?.trim() || `apps/${input.appId}`;
18
+ const mountPath = input.mountPath?.trim() || `/${input.appId}`;
19
+ const packagePath = `${appRoot.replace(/\/+$/, "")}/package.json`;
20
+ const keyList = input.selectedKeys.join(", ");
21
+ const grantRequest = input.vaultAccessMode === "all-apps"
22
+ ? "Dispatch vault access: all saved vault keys are available to every workspace app by default. No per-app vault grants are needed."
23
+ : keyList
24
+ ? `Requested Dispatch vault key grants for this app: ${keyList}`
25
+ : "Requested Dispatch vault key grants for this app: none";
26
+ const resourceList = input.selectedResources.length
27
+ ? input.selectedResources
28
+ .map((resource) => `- ${resource.name} (${resource.kind}, ${resource.path})`)
29
+ .join("\n")
30
+ : "none";
31
+ const scaffoldInstructions = input.scaffoldCommand
32
+ ? ["", "Scaffold instructions:", input.scaffoldCommand]
33
+ : [];
34
+ return [
35
+ "Create a new agent-native app in this workspace.",
36
+ "This is a new workspace app request, not a feature request for the current app.",
37
+ ...scaffoldInstructions,
38
+ "",
39
+ `Suggested app name: ${input.appId} (you may adjust the slug if it conflicts)`,
40
+ `User prompt: ${input.prompt.trim()}`,
41
+ `Generate a concise one-sentence app description from the user prompt before coding; save it in ${packagePath} \"description\" so Dispatch and A2A can describe the app.`,
42
+ "If the user mentions a product or company such as Granola, Loom, Superhuman, Linear, or Notion, treat it as product inspiration unless they explicitly ask to connect to that service. Do not invent or require third-party API keys like GRANOLA_API_KEY just because a product is named.",
43
+ grantRequest,
44
+ `Requested Dispatch workspace resources for this app:\n${resourceList}`,
45
+ "Dispatch workspace resources with scope=all are inherited workspace context. Do not copy or sync them into the new app; every workspace app reads them at runtime and may override with app shared or personal resources.",
46
+ "",
47
+ "Pick a UI template that fits the user's prompt - analytics, assets, brain, calendar, chat, content, design, dispatch, forms, mail, slides, or clips when none of the others fit.",
48
+ 'If you use the chat template, treat it as scaffolding only: the finished app must use the requested app\'s real name, home screen, navigation, package metadata, and manifest, and it must not leave visible "Chat", "Starter", "Blank app", or "New app" UI behind.',
49
+ `Use the workspace app layout: create it under ${appRoot}, mount it at ${mountPath}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
50
+ `Important routing rule: from outside the app, link to ${mountPath}; inside ${appRoot}, React Router routes are app-local. Use <Link to=\"/review\"> and navigate(\"/review\"), not \"${mountPath}/review\"; APP_BASE_PATH supplies the mounted prefix, and hardcoding it causes doubled URLs.`,
51
+ 'Prefer useActionQuery/useActionMutation for actions. If you must raw-fetch framework endpoints, wrap them with agentNativePath("/_agent-native/actions/<name>") so mounted apps call the right URL.',
52
+ `Use relative workspace links like ${mountPath}. Do not hardcode localhost, 127.0.0.1, 8080, 8100, or any dev port; the active workspace gateway or Desktop shell owns the port.`,
53
+ "Use the framework/template UI stack: shadcn/ui components and @tabler/icons-react. Do not add lucide-react or another icon library for standard UI.",
54
+ "Existing first-party apps are neighbors, not implementation details for this app. If the user's prompt mentions Mail, Calendar, Analytics, Brain, Assets, Dispatch, or other templates, treat them as existing hosted/connected apps that this app can link to or call through A2A/default connected agents. For example, Mail, Calendar, Analytics, Brain, and Assets already exist at https://mail.agent-native.com, https://calendar.agent-native.com, https://analytics.agent-native.com, https://brain.agent-native.com, and https://assets.agent-native.com.",
55
+ `Do not create wrapper apps or scaffold child apps/routes for Mail, Calendar, Analytics, Brain, Assets, etc. inside ${appRoot} just so this app can access them. If the request is a cross-app dashboard or overview, build only the new dashboard/overview app and delegate to the existing apps for domain work.`,
56
+ "Only create another first-party app when the user explicitly asks for a customized app from that template; otherwise keep using the hosted/shared app so improvements to the base app keep flowing to users.",
57
+ "Do not satisfy this by adding a route, page, component, or file inside apps/chat or another existing app unless the user explicitly asks to modify that existing app.",
58
+ input.vaultAccessMode === "all-apps"
59
+ ? "Do not create per-app Dispatch vault grants unless the workspace switches vault access to manual or the user explicitly asks for manual grants."
60
+ : keyList
61
+ ? `After the app exists, grant the selected Dispatch vault keys to appId "${input.appId}" and sync them once the app server is available. Treat these as requested grants, not active grants before creation succeeds.`
62
+ : "Do not grant any Dispatch vault keys unless the user asks later.",
63
+ input.selectedResources.length
64
+ ? `After the app exists, grant the selected Dispatch workspace resources to appId "${input.appId}". Do not sync All-app workspace resources; they are inherited.`
65
+ : "Do not grant any selected-only Dispatch workspace resources unless the user asks later.",
66
+ "",
67
+ "App readiness requirements before handing off:",
68
+ `- Ensure ${packagePath} exists with displayName/name and a concise description; Dispatch discovers workspace apps from the workspace filesystem and app metadata.`,
69
+ "- Update the app manifest/package/deploy metadata needed by the existing workspace deployment model.",
70
+ `- Ensure the React Router client entry preserves APP_BASE_PATH/VITE_APP_BASE_PATH so ${mountPath} hydrates correctly.`,
71
+ "- Verify the app's agent card/A2A metadata is ready so Dispatch can discover and delegate to the app after deployment. Every sibling workspace app is available over A2A by default through call-agent, with names and descriptions from the workspace app registry.",
72
+ `When it is ready, start or update the workspace dev server and navigate the user to ${mountPath} on the workspace origin. Do not prefix it with /dispatch/, /apps/, /workspace/, or any other Dispatch tab.`,
73
+ ...(input.additionalInstructions ?? []),
74
+ ].join("\n");
75
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Browser titles must be human-readable strings. React Router stringifies a
3
+ * structured `title` value, which otherwise leaks the whole payload into the
4
+ * browser tab.
5
+ */
6
+ export declare function isHumanReadableDocumentTitle(value: unknown): value is string;
7
+ export declare function normalizeDocumentTitle(value: unknown, fallbackTitle: string): string;
@@ -0,0 +1,29 @@
1
+ const STRUCTURED_TITLE_START = /^[\[{]/;
2
+ /**
3
+ * Browser titles must be human-readable strings. React Router stringifies a
4
+ * structured `title` value, which otherwise leaks the whole payload into the
5
+ * browser tab.
6
+ */
7
+ export function isHumanReadableDocumentTitle(value) {
8
+ if (typeof value !== "string")
9
+ return false;
10
+ const title = value.trim();
11
+ if (!title)
12
+ return false;
13
+ if (!STRUCTURED_TITLE_START.test(title))
14
+ return true;
15
+ try {
16
+ const parsed = JSON.parse(title);
17
+ return parsed === null || typeof parsed !== "object";
18
+ }
19
+ catch {
20
+ return true;
21
+ }
22
+ }
23
+ export function normalizeDocumentTitle(value, fallbackTitle) {
24
+ if (isHumanReadableDocumentTitle(value))
25
+ return value.trim();
26
+ if (isHumanReadableDocumentTitle(fallbackTitle))
27
+ return fallbackTitle.trim();
28
+ return "Agent Native";
29
+ }
@@ -3,6 +3,7 @@ export { agentEnv, type EnvVar } from "./agent-env.js";
3
3
  export { extractOAuthStateAppId } from "./oauth-state.js";
4
4
  export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, decodeContinuation, encodeContinuation, normalizeAppPath, signInJourney, signInJourneyInlineScript, type SignInJourney, type SignInJourneyInput, } from "./sign-in-journey.js";
5
5
  export { truncate } from "./truncate.js";
6
+ export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
6
7
  export { injectDocumentMarkup } from "./html-document.js";
7
8
  export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
8
9
  export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, type RuntimeConfigEnvironment, type RuntimeConfigIssue, type RuntimeConfigIssueCode, type RuntimeConfigIssueSeverity, type RuntimeConfigPhase, type RuntimeConfigReport, type RuntimeConfigRequirements, } from "./runtime-config.js";
@@ -10,6 +11,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, type LlmConnec
10
11
  export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
11
12
  export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, type WorkspaceAppRouteAccess, type WorkspaceAppRouteAccessFromConfig, type WorkspaceAppAudience, } from "./workspace-app-audience.js";
12
13
  export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
14
+ export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, type ChatFirstAppCreationPromptInput, type ChatFirstAppCreationResource, type ChatFirstAppCreationVaultAccessMode, } from "./chat-first-app-creation.js";
13
15
  export { createPollEngine, type PollEngineOptions, type PollEngineHandle, } from "./poll-engine.js";
14
16
  export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, type SocialMetaDescriptor, } from "./social-meta.js";
15
17
  export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
@@ -3,6 +3,7 @@ export { agentEnv } from "./agent-env.js";
3
3
  export { extractOAuthStateAppId } from "./oauth-state.js";
4
4
  export { SIGN_IN_CONTINUATION_MAX_LENGTH, SIGN_IN_CONTINUATION_PARAM, SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, SIGN_IN_LEGACY_RETURN_PARAM, decodeContinuation, encodeContinuation, normalizeAppPath, signInJourney, signInJourneyInlineScript, } from "./sign-in-journey.js";
5
5
  export { truncate } from "./truncate.js";
6
+ export { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "./document-title.js";
6
7
  export { injectDocumentMarkup } from "./html-document.js";
7
8
  export { withBuilderUtmTrackingParams } from "./builder-link-tracking.js";
8
9
  export { buildRuntimeConfigPrompt, formatRuntimeConfigReport, getRuntimeConfigReport, parseRuntimeConfigReport, runtimeConfigRequirementsFromSearchParams, } from "./runtime-config.js";
@@ -10,6 +11,7 @@ export { llmConnectionTrackingProperties, normalizeLlmConnection, } from "./llm-
10
11
  export { DISPATCH_WORKSPACE_ROOT_REDIRECTS, RESERVED_WORKSPACE_APP_IDS, assertValidWorkspaceAppId, getWorkspaceAppIdValidationError, isValidWorkspaceAppIdFormat, } from "./workspace-app-id.js";
11
12
  export { DEFAULT_WORKSPACE_APP_AUDIENCE, WORKSPACE_APP_AUDIENCES, normalizeWorkspaceAppAudience, normalizeWorkspaceAppPathList, workspaceAppAudienceFromEnv, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromEnv, workspaceAppRouteAccessFromPackageJson, } from "./workspace-app-audience.js";
12
13
  export { AGENT_NATIVE_OPEN_PATH, AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, isAgentNativeOpenDeepLink, withCollapsedAgentSidebarParam, } from "./agent-sidebar-url.js";
14
+ export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, } from "./chat-first-app-creation.js";
13
15
  export { createPollEngine, } from "./poll-engine.js";
14
16
  export { AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE, AGENT_NATIVE_SOCIAL_IMAGE_CACHE_BUSTER, AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, defaultSocialImageMeta, withAgentNativeSocialImageCacheBuster, withDefaultSocialImage, } from "./social-meta.js";
15
17
  export { EMBED_MODE_QUERY_PARAM, EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TOKEN_QUERY_PARAM, } from "./embed-auth.js";
@@ -1 +1,17 @@
1
1
  @import "@agent-native/toolkit/chat-history.css";
2
+
3
+ /* Chat-first rails share this geometry across Dispatch and Electron. Keep
4
+ the row at the same compact rhythm as the primary nav and app list. */
5
+ section[data-chat-first-chat-history]
6
+ .an-chat-history--rail
7
+ .an-chat-history-row {
8
+ margin-inline: 0;
9
+ }
10
+
11
+ section[data-chat-first-chat-history]
12
+ .an-chat-history--rail
13
+ .an-chat-history-row__button {
14
+ min-height: 28px;
15
+ padding-block: 4px;
16
+ padding-inline: 8px 32px;
17
+ }
@@ -81,6 +81,13 @@ or other file-like payloads, design the upload path in the same change:
81
81
  provider upload first, then URL/id/blob handle in SQL. Do not add base64/binary
82
82
  columns or stuff files into `application_state`.
83
83
 
84
+ If the feature adds a server-side dependency carrying a native binary or heavy
85
+ runtime — headless browser, ffmpeg, image/video processing, ML runtime — read
86
+ the `performance` skill §9 before adding it. A deployed app has one `/*` page
87
+ function that every visitor's cache miss wakes, and it ships whatever the server
88
+ bundle depends on. Run that work from a background function or a job so the page
89
+ function never carries the weight.
90
+
84
91
  **If the action produces or lists a navigable resource**, add a `link` builder that returns `{ url: buildDeepLink({ app, view, params }), label }`. External coding agents and MCP hosts (Claude / ChatGPT / Claude Code / Cowork / Codex, over MCP/A2A) then surface an "Open in … →" deep link that drops the user back into the running UI focused on the record — for free. If a compatible MCP host should render an inline review/edit surface, also add `mcpApp` with `embedApp()` so the action embeds the real React app route instead of a one-off HTML UI. The `link` builder and `mcpApp` metadata must be pure and synchronous (no I/O). Any external-agent read/ingest action must be `http: { method: "GET" }` + `readOnly: true` + `publicAgent: { expose: true, readOnly: true, requiresAuth: true }`. See the `external-agents` skill.
85
92
 
86
93
  ### 3. Skills / Instructions
@@ -195,4 +202,6 @@ TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultR
195
202
  - **create-skill** — How to create skills for new patterns (area 3 in detail)
196
203
  - **storing-data** — Where to store the feature's data
197
204
  - **real-time-sync** — How the UI stays in sync when the agent writes data
205
+ - **performance** — Query/load cost, and (§9) cold-start artifact size when a
206
+ feature adds a server-side dependency
198
207
  - **internationalization** — How to update localized UI copy and catalogs
@@ -3,8 +3,9 @@ name: turn-into-app
3
3
  description: >-
4
4
  Turn visible project context, a proven thread, skill, or workflow into a
5
5
  runnable Agent-Native app with simple buttons, visible agent steps, preview,
6
- and deployment handoff. Use when a user invokes `/turn-into-app` or asks to
7
- make a workflow into an app, including from Claude or ChatGPT on the web.
6
+ and deployment handoff. Use when a user invokes `/turn-into-app`,
7
+ `/make-into-app`, or asks to make a workflow into an app, including from
8
+ Claude or ChatGPT on the web.
8
9
  user-invocable: true
9
10
  scope: both
10
11
  metadata:
@@ -38,6 +39,15 @@ The build location depends on the host. Treat this as a hard routing rule:
38
39
  workspace, follow the local implementation steps below. The local agent may
39
40
  scaffold, edit, run, and verify the app there.
40
41
 
42
+ Once the source brief is sufficient to identify a repeatable workflow, the
43
+ handoff is non-interactive. Do not ask the user for visual, product, copy,
44
+ layout, template, integration, or implementation choices that can be resolved
45
+ from the source. Select the source's recommended option; otherwise choose the
46
+ most direct conventional default and record the assumption for later review.
47
+ Only stop for a genuine hard blocker such as missing authorization, a
48
+ destructive external action, an ambiguous target workspace, or no identifiable
49
+ workflow at all.
50
+
41
51
  ## Default behavior
42
52
 
43
53
  For a local code-agent runtime this is an end-to-end build skill, not a request
@@ -104,14 +114,16 @@ before creating the app. Read the host-provided context in this order:
104
114
  Record the brief with these headings before handoff: source and provenance,
105
115
  project goal, configuration and constraints, knowledge sources, repeatable
106
116
  workflow, inputs and outputs, judgment and review points, representative runs,
107
- integrations and permissions, and unknowns. This is the compact contract for
117
+ integrations and permissions, and unknowns and assumptions. This is the compact contract for
108
118
  the app. It keeps the new app useful without pretending that hidden Project
109
119
  history was imported. See [the fresh Project reference](references/fresh-project.md)
110
120
  for the host setup and brief template.
111
121
 
112
- If the visible Project context has no concrete repeatable job, ask for one
113
- focused clarification or a representative artifact. Do not fall back to a
114
- generic “what app do you want to make?” builder.
122
+ If the visible Project context has no concrete repeatable job and no primary
123
+ goal can be inferred, ask for one focused clarification or a representative
124
+ artifact. Otherwise use the project's primary goal and source conventions; do
125
+ not ask a questionnaire and do not fall back to a generic “what app do you
126
+ want to make?” builder.
115
127
 
116
128
  ## Source selection guard
117
129
 
@@ -36,7 +36,7 @@ Inputs and outputs:
36
36
  Judgment and review points:
37
37
  Representative runs: none, or 1-3 selected examples
38
38
  Integrations and permissions:
39
- Unknowns and follow-up:
39
+ Unknowns and assumptions:
40
40
  ```
41
41
 
42
42
  Keep source references bounded. Prefer a file name, URL, resource ID, or short
@@ -69,6 +69,13 @@ do not fall back to a local sandbox build. Claude Code and Codex Code are the
69
69
  local-agent exception and may follow the implementation steps in the main
70
70
  skill.
71
71
 
72
+ The brief is an implementation authorization, not a questionnaire. After a
73
+ repeatable workflow is identifiable, choose any source-recommended option
74
+ automatically. For unresolved non-blocking choices, use the most direct
75
+ conventional default, record it under assumptions, and continue. Ask only when
76
+ there is no identifiable workflow, no authorized target workspace, or a
77
+ destructive/credential boundary genuinely prevents the handoff.
78
+
72
79
  In a new Project chat, say:
73
80
 
74
81
  ```text
@@ -81,6 +81,13 @@ or other file-like payloads, design the upload path in the same change:
81
81
  provider upload first, then URL/id/blob handle in SQL. Do not add base64/binary
82
82
  columns or stuff files into `application_state`.
83
83
 
84
+ If the feature adds a server-side dependency carrying a native binary or heavy
85
+ runtime — headless browser, ffmpeg, image/video processing, ML runtime — read
86
+ the `performance` skill §9 before adding it. A deployed app has one `/*` page
87
+ function that every visitor's cache miss wakes, and it ships whatever the server
88
+ bundle depends on. Run that work from a background function or a job so the page
89
+ function never carries the weight.
90
+
84
91
  **If the action produces or lists a navigable resource**, add a `link` builder that returns `{ url: buildDeepLink({ app, view, params }), label }`. External coding agents and MCP hosts (Claude / ChatGPT / Claude Code / Cowork / Codex, over MCP/A2A) then surface an "Open in … →" deep link that drops the user back into the running UI focused on the record — for free. If a compatible MCP host should render an inline review/edit surface, also add `mcpApp` with `embedApp()` so the action embeds the real React app route instead of a one-off HTML UI. The `link` builder and `mcpApp` metadata must be pure and synchronous (no I/O). Any external-agent read/ingest action must be `http: { method: "GET" }` + `readOnly: true` + `publicAgent: { expose: true, readOnly: true, requiresAuth: true }`. See the `external-agents` skill.
85
92
 
86
93
  ### 3. Skills / Instructions
@@ -195,4 +202,6 @@ TL;DR: declare the vocabulary once with `defineAppRoles({ appId, roles, defaultR
195
202
  - **create-skill** — How to create skills for new patterns (area 3 in detail)
196
203
  - **storing-data** — Where to store the feature's data
197
204
  - **real-time-sync** — How the UI stays in sync when the agent writes data
205
+ - **performance** — Query/load cost, and (§9) cold-start artifact size when a
206
+ feature adds a server-side dependency
198
207
  - **internationalization** — How to update localized UI copy and catalogs
@@ -3,8 +3,9 @@ name: turn-into-app
3
3
  description: >-
4
4
  Turn visible project context, a proven thread, skill, or workflow into a
5
5
  runnable Agent-Native app with simple buttons, visible agent steps, preview,
6
- and deployment handoff. Use when a user invokes `/turn-into-app` or asks to
7
- make a workflow into an app, including from Claude or ChatGPT on the web.
6
+ and deployment handoff. Use when a user invokes `/turn-into-app`,
7
+ `/make-into-app`, or asks to make a workflow into an app, including from
8
+ Claude or ChatGPT on the web.
8
9
  user-invocable: true
9
10
  scope: both
10
11
  metadata:
@@ -38,6 +39,15 @@ The build location depends on the host. Treat this as a hard routing rule:
38
39
  workspace, follow the local implementation steps below. The local agent may
39
40
  scaffold, edit, run, and verify the app there.
40
41
 
42
+ Once the source brief is sufficient to identify a repeatable workflow, the
43
+ handoff is non-interactive. Do not ask the user for visual, product, copy,
44
+ layout, template, integration, or implementation choices that can be resolved
45
+ from the source. Select the source's recommended option; otherwise choose the
46
+ most direct conventional default and record the assumption for later review.
47
+ Only stop for a genuine hard blocker such as missing authorization, a
48
+ destructive external action, an ambiguous target workspace, or no identifiable
49
+ workflow at all.
50
+
41
51
  ## Default behavior
42
52
 
43
53
  For a local code-agent runtime this is an end-to-end build skill, not a request
@@ -104,14 +114,16 @@ before creating the app. Read the host-provided context in this order:
104
114
  Record the brief with these headings before handoff: source and provenance,
105
115
  project goal, configuration and constraints, knowledge sources, repeatable
106
116
  workflow, inputs and outputs, judgment and review points, representative runs,
107
- integrations and permissions, and unknowns. This is the compact contract for
117
+ integrations and permissions, and unknowns and assumptions. This is the compact contract for
108
118
  the app. It keeps the new app useful without pretending that hidden Project
109
119
  history was imported. See [the fresh Project reference](references/fresh-project.md)
110
120
  for the host setup and brief template.
111
121
 
112
- If the visible Project context has no concrete repeatable job, ask for one
113
- focused clarification or a representative artifact. Do not fall back to a
114
- generic “what app do you want to make?” builder.
122
+ If the visible Project context has no concrete repeatable job and no primary
123
+ goal can be inferred, ask for one focused clarification or a representative
124
+ artifact. Otherwise use the project's primary goal and source conventions; do
125
+ not ask a questionnaire and do not fall back to a generic “what app do you
126
+ want to make?” builder.
115
127
 
116
128
  ## Source selection guard
117
129
 
@@ -36,7 +36,7 @@ Inputs and outputs:
36
36
  Judgment and review points:
37
37
  Representative runs: none, or 1-3 selected examples
38
38
  Integrations and permissions:
39
- Unknowns and follow-up:
39
+ Unknowns and assumptions:
40
40
  ```
41
41
 
42
42
  Keep source references bounded. Prefer a file name, URL, resource ID, or short
@@ -69,6 +69,13 @@ do not fall back to a local sandbox build. Claude Code and Codex Code are the
69
69
  local-agent exception and may follow the implementation steps in the main
70
70
  skill.
71
71
 
72
+ The brief is an implementation authorization, not a questionnaire. After a
73
+ repeatable workflow is identifiable, choose any source-recommended option
74
+ automatically. For unresolved non-blocking choices, use the most direct
75
+ conventional default, record it under assumptions, and continue. Ask only when
76
+ there is no identifiable workflow, no authorized target workspace, or a
77
+ destructive/credential boundary genuinely prevents the handoff.
78
+
72
79
  In a new Project chat, say:
73
80
 
74
81
  ```text
@@ -4,4 +4,22 @@ export default {
4
4
  appDirectory: "app",
5
5
  ssr: true,
6
6
  routeDiscovery: { mode: "initial" },
7
+
8
+ // Prerendering writes a route's HTML to a static file at build time, so a CDN
9
+ // cache miss serves that file instead of cold-starting the SSR function
10
+ // (seconds of TTFB). It is off here because every route this app ships with is
11
+ // signed-in and personalized, and a prerendered file is served without the
12
+ // auth middleware ever running — freezing the wrong page for every visitor is
13
+ // far worse than a slow first byte.
14
+ //
15
+ // Turn it on only for paths that are all of: publicly reachable, rendered from
16
+ // build-time content alone (no loader data, query string, cookie, session, or
17
+ // database read), and never answering a redirect — prerender would bake a 301
18
+ // into a 200 HTML page. Keep the list in one shared constant and derive the
19
+ // auth plugin's `publicPaths` from it so the two cannot drift:
20
+ //
21
+ // import { PRERENDERED_PUBLIC_PAGE_PATHS } from "./shared/prerendered-public-paths";
22
+ // prerender: { paths: () => [...PRERENDERED_PUBLIC_PAGE_PATHS] },
23
+ //
24
+ // See `.agents/skills/performance/SKILL.md` §9.
7
25
  } satisfies Config;