@jskit-ai/agent-docs 0.1.257 → 0.1.258

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 (230) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +88 -35
  2. package/guide/agent/app-extras/assistant.md +28 -28
  3. package/guide/agent/app-setup/authentication.md +36 -17
  4. package/guide/agent/app-setup/database-layer.md +116 -17
  5. package/guide/agent/app-setup/existing-application-migration.md +29 -25
  6. package/guide/agent/app-setup/multi-homing.md +94 -48
  7. package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
  8. package/guide/agent/framework/client-features.md +496 -0
  9. package/guide/agent/framework/crud-operations.md +5 -5
  10. package/guide/agent/framework/translation.md +4 -3
  11. package/guide/agent/framework/typed-features.md +1104 -0
  12. package/guide/agent/framework/ui-operations.md +2 -2
  13. package/guide/agent/index.md +6 -1
  14. package/package.json +1 -1
  15. package/patterns/feature-package/PATTERN.md +104 -10
  16. package/patterns/feature-package/example/booking-engine/package.json +9 -4
  17. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  18. package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  19. package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  20. package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  21. package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  22. package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
  23. package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  24. package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  25. package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
  26. package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
  27. package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
  28. package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
  29. package/patterns/feature-package/example/variations/types.js +7 -0
  30. package/patterns/minimal-foundation/PATTERN.md +30 -1
  31. package/patterns/minimal-foundation/example/AGENTS.md +14 -0
  32. package/patterns/minimal-foundation/example/bin/develop.js +10 -5
  33. package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
  34. package/patterns/minimal-foundation/example/package.json +5 -4
  35. package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
  36. package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
  37. package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  38. package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  39. package/patterns/minimal-foundation/example/server.js +32 -29
  40. package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  41. package/patterns/shell-foundation/PATTERN.md +29 -0
  42. package/patterns/shell-foundation/example/AGENTS.md +14 -0
  43. package/patterns/shell-foundation/example/bin/develop.js +10 -5
  44. package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
  45. package/patterns/shell-foundation/example/package.json +6 -5
  46. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  47. package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  48. package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
  49. package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
  50. package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  51. package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  52. package/patterns/shell-foundation/example/server.js +32 -29
  53. package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
  54. package/reference/autogen/KERNEL_MAP.md +14 -8
  55. package/reference/autogen/PATTERN_INDEX.md +37 -37
  56. package/reference/autogen/README.md +2 -0
  57. package/reference/autogen/packages/agent-docs.md +70 -26
  58. package/reference/autogen/packages/agent-runtime.md +129 -0
  59. package/reference/autogen/packages/agent.md +149 -0
  60. package/reference/autogen/packages/architecture-inspector.md +97 -44
  61. package/reference/autogen/packages/assistant-core.md +786 -292
  62. package/reference/autogen/packages/assistant-runtime.md +182 -57
  63. package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
  64. package/reference/autogen/packages/assistant-voice.md +54 -8
  65. package/reference/autogen/packages/auth-core.md +44 -13
  66. package/reference/autogen/packages/auth-provider-local-core.md +86 -34
  67. package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
  68. package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
  69. package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
  70. package/reference/autogen/packages/auth-web.md +19 -11
  71. package/reference/autogen/packages/connectors-catalog.md +71 -43
  72. package/reference/autogen/packages/connectors-core.md +42 -4
  73. package/reference/autogen/packages/console-core.md +27 -14
  74. package/reference/autogen/packages/crud-core.md +178 -170
  75. package/reference/autogen/packages/database-runtime-mysql.md +0 -2
  76. package/reference/autogen/packages/database-runtime-postgres.md +0 -2
  77. package/reference/autogen/packages/database-runtime.md +39 -10
  78. package/reference/autogen/packages/http-runtime.md +79 -57
  79. package/reference/autogen/packages/json-rest-api-core.md +11 -8
  80. package/reference/autogen/packages/kernel.md +144 -83
  81. package/reference/autogen/packages/oidc-issuer-core.md +49 -20
  82. package/reference/autogen/packages/payments-core.md +20 -3
  83. package/reference/autogen/packages/realtime.md +47 -22
  84. package/reference/autogen/packages/resource-core.md +1 -1
  85. package/reference/autogen/packages/resource-crud-core.md +64 -26
  86. package/reference/autogen/packages/rewarded-core.md +47 -36
  87. package/reference/autogen/packages/shell-web.md +7 -10
  88. package/reference/autogen/packages/storage-runtime.md +6 -2
  89. package/reference/autogen/packages/uploads-runtime.md +10 -2
  90. package/reference/autogen/packages/users-core.md +73 -71
  91. package/reference/autogen/packages/workspaces-core.md +121 -106
  92. package/reference/autogen/packages/workspaces-web.md +1 -2
  93. package/reference/autogen/tooling/config-eslint.md +302 -0
  94. package/reference/autogen/tooling/jskit-catalog.md +28 -18
  95. package/reference/autogen/tooling/jskit-release.md +35 -20
  96. package/reference/autogen/tooling/testUtils.md +3 -1
  97. package/skills/jskit/SKILL.md +3 -2
  98. package/skills/jskit/references/app-operations.md +1 -1
  99. package/skills/jskit/references/client-features.md +491 -0
  100. package/skills/jskit/references/crud-form-actions.md +1 -1
  101. package/skills/jskit/references/crud-operations.md +7 -7
  102. package/skills/jskit/references/existing-application-migration.md +31 -27
  103. package/skills/jskit/references/heuristics/INDEX.md +5 -1
  104. package/skills/jskit/references/heuristics/child-cruds.md +1 -1
  105. package/skills/jskit/references/heuristics/client-features.md +66 -0
  106. package/skills/jskit/references/heuristics/client-requests.md +1 -1
  107. package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
  108. package/skills/jskit/references/heuristics/crud-links.md +1 -1
  109. package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
  110. package/skills/jskit/references/heuristics/filters.md +1 -1
  111. package/skills/jskit/references/heuristics/live-actions.md +1 -1
  112. package/skills/jskit/references/heuristics/page-redirects.md +1 -1
  113. package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
  114. package/skills/jskit/references/heuristics/placements.md +1 -1
  115. package/skills/jskit/references/heuristics/row-policies.md +1 -1
  116. package/skills/jskit/references/heuristics/server-search.md +1 -1
  117. package/skills/jskit/references/heuristics/surfaces.md +1 -1
  118. package/skills/jskit/references/heuristics/typed-features.md +100 -0
  119. package/skills/jskit/references/heuristics/ui-contract.md +1 -1
  120. package/skills/jskit/references/heuristics/ui-testing.md +4 -4
  121. package/skills/jskit/references/material-3.md +2 -2
  122. package/skills/jskit/references/multi-homing.md +96 -50
  123. package/skills/jskit/references/pattern-index.md +37 -37
  124. package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
  125. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
  126. package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
  127. package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
  128. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
  129. package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
  130. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
  131. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  132. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  133. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
  134. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  135. package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
  136. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
  137. package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
  138. package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
  139. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
  140. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  141. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  142. package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
  143. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
  144. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  145. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  146. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
  147. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
  148. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
  149. package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
  150. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
  151. package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
  152. package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
  153. package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
  154. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  155. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  156. package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
  157. package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
  158. package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
  159. package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
  160. package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
  161. package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
  162. package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
  163. package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
  164. package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
  165. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  166. package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
  167. package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
  168. package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
  169. package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
  170. package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
  171. package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
  172. package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
  173. package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
  174. package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
  175. package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
  176. package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
  177. package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
  178. package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
  179. package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
  180. package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
  181. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
  182. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
  183. package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
  184. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
  185. package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
  186. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  187. package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
  188. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
  189. package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
  190. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  191. package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
  192. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  193. package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
  194. package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
  195. package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
  196. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
  197. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  198. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  199. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  200. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  201. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  202. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
  203. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  204. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  205. package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
  206. package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
  207. package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
  208. package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
  209. package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
  210. package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
  211. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
  212. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
  213. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
  214. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
  215. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
  216. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
  217. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
  218. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
  219. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
  220. package/skills/jskit/references/translation.md +5 -4
  221. package/skills/jskit/references/typed-features.md +1099 -0
  222. package/skills/jskit/references/ui-operations.md +3 -3
  223. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  224. package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
  225. package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  226. package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
  227. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  228. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
  229. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  230. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
@@ -93,7 +93,7 @@ as not sent with `conversation_message_cancelled`. It also stops a submission
93
93
  that holds the message, and afterwards discards its unconfirmed request or
94
94
  pending native attempt. A message already accepted stays history. An
95
95
  application conversation provides this as `cancelDelivery({ messageId })`;
96
- without it the operation answers `conversation_unsupported`. Browser inputs cannot set the actor,
96
+ without it the operation answers `conversation_message_cancel_unsupported`. Browser inputs cannot set the actor,
97
97
  native host or engine context.
98
98
  `readConversation(id, { beforeTurnId, limit, signal })` optionally requests an
99
99
  earlier or bounded page through the same authenticated GET. Its query contains
@@ -1120,8 +1120,8 @@ separate concerns.
1120
1120
  ## Optional shared capabilities
1121
1121
 
1122
1122
  All capabilities below are optional. Omit their adapter field to leave them off.
1123
- They work in the aggregate element and as separately exported components; Vibe64
1124
- uses the same components with its native transport and project policy.
1123
+ They work in the aggregate element and as separately exported components; a hosted
1124
+ editor can use the same components with its native transport and project policy.
1125
1125
  Configuration UI never grants backend permissions.
1126
1126
 
1127
1127
  ### Working status and suggestions
@@ -1312,7 +1312,7 @@ adapter.attachments = reactive(useAssistantAttachments({
1312
1312
  ```
1313
1313
 
1314
1314
  `sessionId` is an opaque application upload scope, such as a conversation or
1315
- session identifier. It does not require Vibe64. The application owns routes,
1315
+ session identifier. It does not require a hosted editor. The application owns routes,
1316
1316
  authentication, storage, limits, inspection, retention and provider file access.
1317
1317
  An upload returns `{ attachmentId, fileName, size }` with optional `reference` and
1318
1318
  application fields. Progress reports use `{ loaded, total }`. The controller
@@ -1479,7 +1479,7 @@ history, sends, stops, deletion and attachment reads. The memory reference
1479
1479
  adapter requires a nonempty string; other adapters may use structured scopes.
1480
1480
 
1481
1481
  Each callback receives these asynchronous operations. The first six serve the
1482
- transcript service. All nine are mandatory for `createConversationRuntime()`:
1482
+ transcript service. All the others are mandatory for `createConversationRuntime()`:
1483
1483
 
1484
1484
  | Transaction operation | Contract |
1485
1485
  | --- | --- |
@@ -1493,6 +1493,9 @@ transcript service. All nine are mandatory for `createConversationRuntime()`:
1493
1493
  | `readMetadata()` | Detached conversation metadata object; return `{}` for an empty scope. |
1494
1494
  | `writeMetadata(value)` | Replace conversation metadata within this transaction, committing atomically with its turn/message changes. |
1495
1495
  | `updateTurnMetadata(turnId, patch)` | Shallow-merge a detached patch into an existing turn's metadata; preserve unrelated keys and reject absent turns. |
1496
+ | `readTurnsAfter(turnId)` | Detached snapshots of the turns after that turn, oldest first, as `readTurn` returns them; `""` reads every turn. Reject an absent turn. |
1497
+ | `readSummary()` | The API compaction summary `{ text, throughTurnId }` (the last turn it covers), detached, or null. |
1498
+ | `writeSummary({ text, throughTurnId })` | Replace that summary within this transaction; reject empty text or an absent turn. Messages are never deleted. |
1496
1499
 
1497
1500
  `write` serializes mutations for the same scope, including duplicate checks and
1498
1501
  ID allocation. A successful return means the write is durable for that adapter.
@@ -1505,6 +1508,9 @@ Reads must not expose mutable backing objects.
1505
1508
  Use storage-level locks or transactions when several processes share storage;
1506
1509
  an in-process promise queue alone does not provide that guarantee.
1507
1510
 
1511
+ `readConversationLog(scope, { afterTurnId })` reads only the turns after that turn,
1512
+ through the transaction's `readTurnsAfter`.
1513
+
1508
1514
  The service exposes `readConversationLog`, `readConversationLogPage`,
1509
1515
  `conversationMessageIdExists`, `writeConversationUserMessage`,
1510
1516
  `writeConversationAssistantMessage`, `writeConversationThinkingMessage`,
@@ -1536,7 +1542,8 @@ await verifyConversationStorageContract(storage, { runtime: true });
1536
1542
  Those checks cover scoped isolation, concurrent duplicate writes, stable
1537
1543
  ordering, pagination, final replacement, attachments and detached reads. An
1538
1544
  adapter selected with `runtime: true` also checks all metadata operations, scope
1539
- isolation, patch preservation and combined transcript/metadata rollback. Use a
1545
+ isolation, patch preservation, combined transcript/metadata rollback, reading the
1546
+ turns after a turn and the saved, scoped and rolled-back compaction summary. Use a
1540
1547
  fresh isolated fixture for each invocation; omit the option only for transcript-only
1541
1548
  adapters. An app must additionally test its authentication, crash/reopen behavior,
1542
1549
  multi-process writes, failed commits and attachment cleanup.
@@ -2390,7 +2397,8 @@ the same transaction. The file adapter remains one-writer storage.
2390
2397
 
2391
2398
  `createConversationStorage({ readRecord, writeRecord, deleteRecord, recordVersion })` is exported
2392
2399
  for custom single-writer record stores. Each record contains `{ turns: Map,
2393
- metadata: object }`; a missing record uses an empty map and metadata object. Its
2400
+ metadata: object }` and, once an API conversation is compacted, `summary: { text,
2401
+ throughTurnId }`; a missing record uses an empty map and metadata object. Its
2394
2402
  copy-on-write transaction methods match the supplied memory/file adapters. Saved
2395
2403
  records are shared and never changed in place; a transaction copies only the turn
2396
2404
  map and the turns it changes. The optional `recordVersion(id)` returns a cheap
@@ -2405,26 +2413,69 @@ serializes writes through one instance, not across processes. A database-backed
2405
2413
  application with concurrent writers must implement `read`/`write` using its own
2406
2414
  database transaction or hold that transaction across record loading and commit.
2407
2415
 
2408
- The current API driver supports application action tools and authorized attachments.
2409
- It reports steering and native goals as unsupported. Limits can bound input, output and history characters, output
2410
- tokens and request duration. Oversized history fails explicitly; it is not silently
2411
- truncated or presented as native compaction. These capabilities will be extended
2412
- as their shared integrations are migrated.
2413
-
2414
- API replies use the shared streaming completion parser. Internal reasoning and
2415
- provider tool markup stay out of visible replies, including tags split across
2416
- chunks. Structured and text-encoded application calls use the same authorized
2417
- execution and saved receipts. A completed response is required before executing
2418
- a call; interrupted streams do not imply permission to execute or retry it.
2419
- Output limits count raw provider text, including hidden blocks. Code indentation
2420
- and blank lines remain intact in ordinary API answers.
2416
+ The API driver runs each reply on the agent engine, `@jskit-ai/agent`. It supports
2417
+ application action tools and authorized attachments, and reports steering and native
2418
+ goals as unsupported. Limits can bound input and output characters, output tokens,
2419
+ steps and request duration. `limits.maxOutputCharacters` bounds each step's text
2420
+ and the final reply; reasoning is bounded by output tokens instead.
2421
+
2422
+ A long conversation is compacted rather than refused. `limits.contextTokens`
2423
+ (default 128,000) is the model's window, and the engine's sizes scale to it. Past
2424
+ the engine's compaction point, everything but the latest turns is folded into a
2425
+ summary written for the model, and storage keeps that summary with the last turn
2426
+ it covers (`writeSummary`). Later turns read only the turns after it
2427
+ (`readTurnsAfter`) and send the summary in the system prompt; messages are never
2428
+ deleted. Should compacting fail, the engine's last-resort cut drops the oldest
2429
+ messages and tells the model so. A bound conversation's host owns its transcript,
2430
+ so it is not compacted, and history an application supplies as `apiHistory` is
2431
+ used as given. History turns within the newest 20 messages send their files again;
2432
+ older turns name their files without their content.
2433
+
2434
+ Each reply streams one message per step: `reply-1`, `reply-2` and so on. A step
2435
+ that also calls actions ends as commentary, complete before the first of its actions
2436
+ runs, and the reply's last step becomes the answer. The answer leaves out words already shown as commentary, unless they are
2437
+ all the reply says. Reasoning a model writes inline in `<think>` tags is kept as
2438
+ reasoning, including tags split across chunks. Provider tool markup and DeepSeek's
2439
+ own tokens never reach visible text, and a call written out as text never runs: the
2440
+ markup check below tells the model so. Every structured action call runs through
2441
+ the same authorized execution and saved receipts; a call to an action the model was
2442
+ not given is answered as a tool error, and nothing runs or is saved for it. A
2443
+ failed action reaches the model as its error; an unknown outcome or a broken
2444
+ receipt ends the reply at once with its error. A completed step is required before
2445
+ any of its calls runs.
2446
+ Results of earlier turns past 6,000 characters are cut, and the third, fifth and
2447
+ eighth identical call in a row tells the model it is not making progress.
2448
+
2449
+ A finished reply gets the engine's checks. Each sends it back once to carry on from
2450
+ its own steps: raw markup (nothing in it ran), a reply that stops at announcing
2451
+ its next step, and, when neither ran, a claimed action that the reply's own
2452
+ actions do not support (one short model call compares them). The completion
2453
+ metadata names the check as `check`. A reply that ends with the engine's own
2454
+ account of where it got to is never sent back as stopping short.
2455
+
2456
+ A reply runs at most `limits.maxSteps` steps (default 40, the engine's limit for
2457
+ work with app tools). Out of steps, or past the engine's 15-minute reply deadline,
2458
+ it ends with the model's own short account of what it did and what is left, and
2459
+ the completion metadata says why as `unfinished`. Failed model calls are tried
2460
+ again six times with growing waits (or the provider's retry-after), about two
2461
+ minutes in all. When nothing has been done yet, the call's error fails the turn as
2462
+ status information; after some steps, the engine's account ends the reply instead.
2463
+
2464
+ Admission precedes every model call. The first resolves the authorized connection,
2465
+ checks access and admits the request; every later call (steps, checks, summaries,
2466
+ accounts) authorizes the same connection again and stops the reply when access is
2467
+ gone. A configured `effort` reaches every provider as the AI SDK's standard
2468
+ reasoning setting; without one, the engine's default applies (adaptive thinking at
2469
+ high effort for Anthropic-format models). The system prompt is the configured
2470
+ instructions, then the summary, then the engine's state note with the current UTC
2471
+ time.
2421
2472
 
2422
2473
  An application can set server-owned `limits.maxApiToolProgressCharacters` to a
2423
2474
  positive safe integer to bound the decoded text accompanying confirmed API tool
2424
2475
  calls. The API driver rejects oversized progress before executing any call from
2425
2476
  that response; it does not clip the text or ask the model to repeat the operation.
2426
2477
  Omit the limit to retain the original API policy. It does not change final-answer
2427
- limits or the original sixteen tool rounds and three recovery passes. This option
2478
+ limits or the step limit. This option
2428
2479
  applies only to the direct API carrier; native tool progress needs association
2429
2480
  with its exact admitted native use at that engine's execution boundary.
2430
2481
 
@@ -2440,14 +2491,9 @@ OpenCode delivery recovery applies the bound to the joined decoded native reply
2440
2491
  while retaining the proven user admission and avoiding another inference. An advanced
2441
2492
  host supplying its own native runtime retains that runtime's writer policy.
2442
2493
 
2443
- The API driver uses the existing assistant tool-loop policy: up to sixteen tool
2444
- rounds, then three recovery passes with tools disabled. Progress-only narration
2445
- is retained as commentary rather than accepted as the final answer. An available
2446
- clock action marked `current-time` runs before inference for time questions only
2447
- when it requires no parameters, after connection authorization and turn admission.
2448
- Uncertain application effects stop the turn; recovery never silently retries them.
2449
- The legacy database service delegates to the same loop through its transactional
2450
- adapter over the existing conversation, message and request-claim rows.
2494
+ The state note carries the current time; no action runs before inference. Uncertain application effects stop the turn; nothing
2495
+ silently retries them. The legacy database service delegates to the same driver through its
2496
+ transactional adapter over the existing conversation, message and request-claim rows.
2451
2497
 
2452
2498
  ### Authorized attachments
2453
2499
 
@@ -2545,7 +2591,8 @@ or application turn owns separate call identities, even if the model reuses an
2545
2591
  ID. An interrupted reservation without a
2546
2592
  result or a server failure after execution stops the turn with an unknown-outcome
2547
2593
  error instead of executing again. Applications
2548
- still own action-level idempotency and inspection of uncertain external effects.
2594
+ still make each action tolerate a repeated request in its own domain, and
2595
+ inspect uncertain external effects.
2549
2596
  The runtime cannot infer whether two different call IDs mean the same mutation.
2550
2597
 
2551
2598
  Events with `type: "tool"` carry the call's `id`, `name`, `arguments`, `status` and,
@@ -2769,8 +2816,8 @@ execution identity remains the filesystem boundary for those tools.
2769
2816
 
2770
2817
  Install Claude Code and log in with `claude auth login` under the application's
2771
2818
  server identity. The ordinary single-user host uses that account and owned POSIX
2772
- process groups. It requires no Vibe64, Genesis or application-specific startup
2773
- callbacks:
2819
+ process groups. It requires no hosted editor, project tooling or application-specific
2820
+ startup callbacks:
2774
2821
 
2775
2822
  ```js
2776
2823
  const runtime = createConversationRuntime({
@@ -3535,6 +3582,12 @@ facilities before inspecting its own native state. Its history-idle query reads
3535
3582
  that same state; the host separately checks durable process receipts and actual
3536
3583
  terminal activity. No second activity cache or restoration loop is required.
3537
3584
 
3585
+ The application that creates the owner may pass its own error builder as
3586
+ `createError(message, { code })`. Every refusal the owner raises passes its own
3587
+ code, such as `conversation_claude_session_closing` or
3588
+ `conversation_claude_message_required`, so the builder forwards that code
3589
+ instead of giving every refusal the same one.
3590
+
3538
3591
  The owner serializes preparation with native controls and preserves the original
3539
3592
  control-interrupt followed by mandatory process drain. A failed drain stays an
3540
3593
  error. The host retains execution policy, durable cleanup and publication at
@@ -3721,7 +3774,7 @@ acknowledgement, stream blocks, nested-event exclusion, background-task
3721
3774
  completion and the interruption barrier for steering. Normalized owner events
3722
3775
  let the host persist admissions and publish application state; receiver
3723
3776
  completion alone does not prove process exit. `claudeNativeMessageId()`
3724
- retains the same stable native message IDs used by the Vibe64 adapter.
3777
+ retains the same stable native message IDs that a host's own adapter uses.
3725
3778
  An exact native acknowledgement ends its ACK deadline before the admission
3726
3779
  writer runs; a slow write remains awaited, and a rejected write rejects admission.
3727
3780
  A missing acknowledgement remains uncertain. Native failure-result text stays
@@ -3933,8 +3986,8 @@ sandbox or resource limiter. It does not grant a permission bypass by default.
3933
3986
  The native executable and its account login must already exist. Call `stop()`
3934
3987
  and await its proof on shutdown; closing the protocol stream alone does not
3935
3988
  prove that native work stopped. Failed cleanup remains an error or an unconfirmed
3936
- proof, and the owning application must retain its stop handle. Managed applications
3937
- such as Vibe64 replace execution to enforce identity, resources and scope cleanup.
3989
+ proof, and the owning application must retain its stop handle. Managed hosts
3990
+ replace execution to enforce identity, resources and scope cleanup.
3938
3991
 
3939
3992
  For native history retirement, `nativeConversationStoragePolicy(engineId)` from
3940
3993
  `/server/conversation` describes the engine's writer requirements. Codex's native
@@ -369,6 +369,12 @@ must have a documented exclusion or a description, output contract, result adapt
369
369
  and execution fixture. Application-defined automation actions require the same
370
370
  review; automation capability alone does not mean model exposure is safe.
371
371
 
372
+ An application test that checks which actions a surface's assistant offers, or
373
+ calls them as the assistant would, builds the catalogue the runtime builds:
374
+ `createSurfaceAwareToolCatalog(actions, { appConfig })` from
375
+ `@jskit-ai/assistant-runtime/server`, with the application's `runtime.actions`
376
+ and its server configuration. Each call names its surface in `context.surface`.
377
+
372
378
  Generated list and view actions use JSON:API query shapes directly. `include`
373
379
  is a comma-separated string, and `fields` is keyed by resource type:
374
380
 
@@ -432,8 +438,7 @@ catalog by opting it in explicitly:
432
438
  ```js
433
439
  extensions: {
434
440
  assistant: {
435
- alwaysAvailable: true,
436
- preflight: ["current-time"]
441
+ alwaysAvailable: true
437
442
  }
438
443
  }
439
444
  ```
@@ -446,32 +451,27 @@ lookup before discovery-mode execution.
446
451
  ### Database surface conversation lifecycle
447
452
 
448
453
  The client receives answer text incrementally and shows working status before
449
- text arrives. Tool calls produce timeline events. Internal reasoning tags and raw
450
- tool arguments do not become visible answer text. A tool/recovery round replaces
451
- its provisional answer; completed answers occupy the existing chat rows.
452
- Common runtime commentary is retained separately from those chat rows. Progress-only
453
- responses such as “Let me query…” may appear provisionally while streaming but
454
- are retried internally and never stored or replayed as final chat history.
455
-
456
- The runtime permits up to 16 bounded tool rounds so catalog search, contract
457
- lookup, and execution can complete in one turn. If ordinary tool-failure
458
- recovery cannot finish, the runtime returns the latest successful tool result
459
- with a 4,000-character cap, or a concise failure when there was no successful
460
- result. Genuine round-budget exhaustion ends with exactly `Limit reached. Start
461
- a new conversation.`
462
-
463
- For current or relative date and time questions, the runtime instructs the
464
- model to use an available authoritative workspace clock action. When an
465
- authorized `preflight: ["current-time"]` action has no model-required input,
466
- the runtime executes it before the first model completion and places its result
467
- in model history. Mark it `alwaysAvailable` when the authorized catalog can
468
- enter discovery mode. Trusted workspace input can still be required by the
469
- application because JSKIT hides and injects it before execution.
470
-
471
- The clock action and its timezone policy remain application-owned; JSKIT does
472
- not invent a clock action or infer the current date from model knowledge. Make
473
- that action automation-capable and available on the assistant surface if the
474
- product needs now, today, tomorrow, or other relative-date answers.
454
+ text arrives. Tool calls produce timeline events. Internal reasoning, provider tool
455
+ markup and raw tool arguments do not become visible answer text. Each model step
456
+ streams its own provisional answer; a step that also calls actions is kept as
457
+ commentary, separately from the chat rows, and the last step becomes the completed
458
+ answer in the existing chat rows.
459
+
460
+ Replies run on the agent engine (`@jskit-ai/agent`), up to 40 steps by default, so
461
+ catalog search, contract lookup and execution can complete in one turn. A failed
462
+ action reaches the model as its error. A reply that runs out of steps ends with
463
+ the model's own account of what it did and what is left. The engine's checks send
464
+ a reply back once when it leaks markup, stops at announcing its next step (“Let me
465
+ query…”), or claims an action no tool performed. Long conversations are summarised
466
+ rather than refused; see the conversation runtime guide.
467
+
468
+ Every request carries the current date and time in UTC in the engine's state
469
+ note, so no turn needs an extra action to learn it, and no action runs before
470
+ the model asks for one. The workspace's own time
471
+ zone and clock remain application-owned: when answers need local now, today or
472
+ tomorrow, make a clock action automation-capable, available on the assistant
473
+ surface and `alwaysAvailable` when the catalog can enter discovery mode, and the
474
+ model calls it like any other action.
475
475
 
476
476
  Conversation restoration loads every transcript page needed to retain the
477
477
  newest bounded transcript window, so a completed response on page two does not
@@ -44,12 +44,15 @@ An application with accounts always includes the managed-preview login, whether
44
44
  or not anyone asked for it. Adding authentication adds both parts from the
45
45
  `auth/auth-surface` pattern:
46
46
 
47
- - the committed, executable `tools/preview-identity` from its example;
48
- - the `#### Preview identity` block in the web-presented Vibe64 `Outputs`
49
- target (Command `tools/preview-identity`, Protocol
50
- `vibe64.preview-identity.command.v1`, Identity types `email` `user-id`,
51
- Enabled environment `AUTH_DEV_BYPASS_ENABLED`, Secret environment
52
- `AUTH_DEV_BYPASS_SECRET`, Runtimes `nodejs`), copied exactly from the pattern.
47
+ - the committed, executable `tools/preview-identity` from its example, which
48
+ passes `runManagedPreviewIdentityCommand` the preview host's protocol id, the
49
+ hostnames, besides loopback, that the host serves the app on, and the process
50
+ environment;
51
+ - its declaration to the preview host in the form that host reads (for a host
52
+ that reads the web `Outputs` target, the pattern's `#### Preview identity`
53
+ block: Command `tools/preview-identity`, the same protocol id, Identity types
54
+ `email` `user-id`, Enabled environment `AUTH_DEV_BYPASS_ENABLED`, Secret
55
+ environment `AUTH_DEV_BYPASS_SECRET`, Runtimes `nodejs`).
53
56
 
54
57
  The preview host supplies both environment values per run, so a managed
55
58
  preview can sign its browser in as an existing account. Which accounts it may
@@ -76,32 +79,48 @@ capability using an ordinary application provider:
76
79
 
77
80
  ```js
78
81
  import { defineProvider } from "@jskit-ai/kernel/shared/capabilities";
82
+ import { createRecoverySender } from "./recoverySender.js";
79
83
 
80
84
  export const RecoveryEmailProvider = defineProvider({
81
85
  id: "app.recovery-email",
82
86
  requires: { mail: "app.mail" },
83
87
  provides: { recoverySender: "auth.local.recovery-sender" },
88
+ /** @param {{ mail: import("@local/mail/server/types").AppMail }} capabilities */
84
89
  setup({ mail }) {
85
- return {
86
- recoverySender: async ({ email, recoveryUrl }) => {
87
- await mail.send({
88
- to: email,
89
- subject: "Reset your password",
90
- text: `Open this link to reset your password:\n\n${recoveryUrl}\n`
91
- });
92
- }
93
- };
90
+ return { recoverySender: createRecoverySender({ mail }) };
94
91
  }
95
92
  });
96
93
  ```
97
94
 
95
+ ```js
96
+ // recoverySender.js
97
+ /** @param {{ mail: import("@local/mail/server/types").AppMail }} dependencies */
98
+ function createRecoverySender({ mail }) {
99
+ /** @type {import("@jskit-ai/auth-provider-local-core/server/types").AuthLocalRecoverySender} */
100
+ async function sendRecoveryEmail({ email, recoveryUrl }) {
101
+ await mail.send({
102
+ to: email,
103
+ subject: "Reset your password",
104
+ text: `Open this link to reset your password:\n\n${recoveryUrl}\n`
105
+ });
106
+ }
107
+
108
+ return sendRecoveryEmail;
109
+ }
110
+
111
+ export { createRecoverySender };
112
+ ```
113
+
98
114
  `app.mail` is an application-owned capability in this example, not a built-in
99
115
  JSKIT email API. Its `send()` implementation owns the selected integration,
100
116
  credential resolution and safe error mapping. A connected account or a domain
101
117
  listing adapter alone does not implement email sending. Install this provider
102
118
  alongside the application's mail provider and `AuthLocalProvider`.
119
+ [Typed features](/guide/framework/typed-features) describes how application
120
+ providers name and type the capabilities they receive.
103
121
  For direct library composition, pass the same function as `recoverySender` to
104
- `createLocalAuthService()`.
122
+ `createLocalAuthService()`, with a configuration from
123
+ `resolveLocalAuthConfig({ appRoot, env, fileBackend, emailRecovery: true })`.
105
124
 
106
125
  Set `APP_PUBLIC_URL` to the application's actual public URL. When a sender is
107
126
  configured, auth requires this value and does not return or log the recovery
@@ -213,7 +232,7 @@ in the server process and use `loginAsExistingUser()` from
213
232
  client environment.
214
233
 
215
234
  A managed host instead supplies authenticated state through
216
- `VIBE64_PLAYWRIGHT_STORAGE_STATE` and the app-owned Playwright config. Treat the
235
+ `PLAYWRIGHT_STORAGE_STATE` and the app-owned Playwright config. Treat the
217
236
  file as a temporary secret, use relative URLs, and do not call the localhost
218
237
  login helper or start a duplicate server.
219
238
 
@@ -54,14 +54,20 @@ application file is small:
54
54
  import { createKnexMigrationConfigFromApp } from
55
55
  "@jskit-ai/database-runtime/server/knexMigrationConfig";
56
56
 
57
- export default await createKnexMigrationConfigFromApp({ client: "mysql2" });
57
+ export default await createKnexMigrationConfigFromApp({ client: "mysql2", environment: process.env });
58
58
  ```
59
59
 
60
- Use `client: "pg"` for PostgreSQL. The complete examples are in:
60
+ Use `client: "pg"` for PostgreSQL. The environment is always passed: JSKIT reads
61
+ the connection values from what the application gives it, never from
62
+ `process.env` on its own. The complete examples are in:
61
63
 
62
64
  - `database/mysql-application`
63
65
  - `database/postgres-application`
64
66
 
67
+ Each example is complete for its own engine. Copy files only from the selected
68
+ driver's pattern and never merge the two; for example, the CI workflow must
69
+ contain only that engine's database service.
70
+
65
71
  The config discovers migrations directly from the current installed package
66
72
  graph. Application migrations live in the app's `migrations/` directory;
67
73
  package-owned migrations live in directories declared by the installed
@@ -111,6 +117,30 @@ package's metadata:
111
117
  }
112
118
  ```
113
119
 
120
+ A `constraints/` subdirectory of a declared directory, such as
121
+ `migrations/constraints/`, holds the package's constraints migrations; it runs
122
+ later, as described below.
123
+
124
+ A package whose table migrations use another package's tables names that
125
+ package in `after`, and its migrations, and its constraints, then run after
126
+ that package's:
127
+
128
+ ```json
129
+ {
130
+ "jskit": {
131
+ "migrations": {
132
+ "directories": ["migrations"],
133
+ "after": ["@jskit-ai/users-core"]
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ Each name in `after` must be another installed JSKIT package; a name that is
140
+ not installed, the package's own name, or packages that each name the other
141
+ stop discovery with an error. A named package without migrations orders
142
+ nothing.
143
+
114
144
  Names must remain unique across the effective migration directories. Preserve
115
145
  the basename when relocating a migration: Knex records that name in its ledger.
116
146
  Do not rename it to force execution or edit an already-applied migration's body;
@@ -121,24 +151,60 @@ changed schema behavior requires a new migration.
121
151
  `createKnexMigrationConfigFromApp()` sets `sortDirsSeparately: true` and runs
122
152
  pending migrations in this order, using the default `migrationsDirectory`:
123
153
 
124
- 1. Application `migrations/`.
125
- 2. Discovered package migration directories, sorted by their absolute paths
126
- using `localeCompare`.
127
- 3. Application `migrations/constraints/`.
154
+ 1. Discovered package migration directories, sorted by their absolute paths
155
+ using `localeCompare`, except that a package's directories follow those of
156
+ every package its `after` names, which follow theirs in turn, each in the
157
+ order listed. Without `after` the path order is unchanged.
158
+ 2. Application `migrations/`.
159
+ 3. The `constraints/` subdirectory of each discovered package migration
160
+ directory that has one, in the same order.
161
+ 4. Application `migrations/constraints/`.
128
162
 
129
163
  Knex sorts filenames within each directory, not across the whole graph; see
130
164
  its [`sortDirsSeparately` option](https://knexjs.org/guide/migrations.html#migration-api).
131
- Package discovery does not topologically order tables or foreign keys. A newer
132
- timestamp in an earlier package still runs before every file in a later package.
165
+ Package discovery does not read tables or foreign keys; only `after` changes
166
+ the package order. A newer timestamp in an earlier package still runs before
167
+ every file in a later package.
133
168
  Inspect the effective `knexfile.js` configuration if the app customizes it.
134
169
 
135
- Keep table and column creation with the owning package. Put cross-package
136
- foreign keys and other constraints that need the complete package schema in
137
- application `migrations/constraints/`. An ordinary root `migrations/` file runs
138
- too early for this purpose. For example, a `pet_notes.product_id` column can be
170
+ Every package table exists before the application's own migrations run, so a
171
+ root `migrations/` file can reference a package table directly, for example a
172
+ `books.user_id` foreign key to `users.id`. A package's table migrations must
173
+ never depend on an application table.
174
+
175
+ Keep table and column creation with the owning package. Put foreign keys
176
+ between two packages, and other constraints that need the complete schema, in a
177
+ constraints phase: the referencing package's own `constraints/` subdirectory
178
+ when it ships the key, or application `migrations/constraints/`. A package
179
+ constraints migration runs after the application's `migrations/`, so it can also
180
+ reference a table that may belong to the application, such as `users`; for
181
+ example, `@jskit-ai/assistant-runtime` adds its `users` and `workspaces` keys
182
+ from `migrations/constraints/`. Similarly, a `pet_notes.product_id` column can be
139
183
  added by the pet-notes package, but its foreign key to the products package's
140
- `products.id` belongs in the final constraints phase. Do not rely on today's
141
- package-directory order to make a cross-package reference work.
184
+ `products.id` belongs in a constraints phase. Do not rely on the
185
+ package-directory path order to make a cross-package reference work; when a
186
+ package's table migrations need another package's table, declare `after`.
187
+
188
+ Until `@jskit-ai/database-runtime` 0.1.252, root `migrations/` ran before the
189
+ package directories, so a fresh database failed on any application migration
190
+ that referenced a package table. Applied migrations stay in the Knex ledger;
191
+ only pending ones follow the new order. An application migration that still
192
+ creates a package-owned table belongs in that package.
193
+
194
+ The assistant-runtime, console-core and rewarded-core table migrations used to
195
+ add their keys to `users`, `workspaces` and later tables inline. A fresh MySQL
196
+ or MariaDB database failed when the parent table did not exist yet (errno 150),
197
+ and the assistant tables silently skipped their `workspaces` keys. They now add
198
+ them from `migrations/constraints/`. A database migrated earlier keeps the keys
199
+ it already has, and gains any that are missing.
200
+
201
+ `@jskit-ai/database-runtime/server/foreignKeyMigrations` serves constraints
202
+ migrations that must run on fresh and already-migrated databases alike.
203
+ `addMissingForeignKey(knex, key)` adds a single-column key only when no key
204
+ already links that column to the parent column. It fails, naming the table,
205
+ column and count, when rows have no parent, and it deletes nothing; repair
206
+ those rows and migrate again. `dropForeignKeyIfPresent(knex, key)` serves
207
+ `down()`.
142
208
 
143
209
  Before adding the key, check that both tables and columns exist, the referenced
144
210
  key is indexed appropriately, column types match (including integer signedness),
@@ -206,7 +272,40 @@ Repositories own database access. Services and lifecycle hooks orchestrate
206
272
  repositories. External delivery belongs after commit; when it must be durable,
207
273
  write an outbox record inside the transaction and deliver it separately.
208
274
  A separate Feature is warranted when an operation belongs to another domain,
209
- not merely because a useful resource has behavior beyond list and save.
275
+ not merely because a useful resource has behavior beyond list and save. Write
276
+ it as a [typed feature](/guide/framework/typed-features).
277
+
278
+ ## Optimistic locking
279
+
280
+ A CRUD resource whose records carry a version number names it with
281
+ `lockVersionField`, an integer schema field over a non-null integer column
282
+ with a starting value, such as `0`:
283
+
284
+ ```js
285
+ defineCrudResource({
286
+ namespace: "contracts",
287
+ tableName: "contracts",
288
+ autofilter: "workspace",
289
+ lockVersionField: "lockVersion",
290
+ schema: {
291
+ // ...
292
+ lockVersion: { type: "integer", min: 0, readOnly: true, column: "lock_version" }
293
+ }
294
+ });
295
+ ```
296
+
297
+ The CRUD repository's
298
+ `patchDocumentIfLockVersion(recordId, expectedLockVersion, patch, { trx, context })`
299
+ then applies `patch` only while the record still holds `expectedLockVersion`, a
300
+ non-negative integer, and adds one to the lock version in the same
301
+ transaction: the caller's `trx`, or one it owns. It returns the patched document, which carries the new lock
302
+ version, or `null` when the record does not exist or is outside the caller's
303
+ scope. A record whose lock version has moved on rejects with a 409 coded
304
+ `crud.document.lockVersionConflict` ("This record changed. Reload and try
305
+ again."), and nothing is written. The patch leaves the lock field out; an app
306
+ that wants its own wording for the conflict catches that code. A resource
307
+ without `lockVersionField` cannot call it, and `defineCrudResource()` rejects
308
+ a `lockVersionField` that names no integer schema field.
210
309
 
211
310
  ## Deadlock retries
212
311
 
@@ -218,8 +317,8 @@ request instead of a 500. This applies to `runInTransaction()` and
218
317
  `createWithTransaction()` from `@jskit-ai/database-runtime/shared`, to
219
318
  `transactionManager.inTransaction()`, to the seed transaction, to every JSON
220
319
  REST repository's `withTransaction()` (CRUD, users and workspaces), and to a
221
- CRUD `createDocument`, `patchDocumentById` or `deleteDocumentById` given no
222
- `trx`, which owns its own transaction. A lock wait timeout (errno 1205) is not
320
+ CRUD `createDocument`, `patchDocumentById`, `patchDocumentIfLockVersion` or
321
+ `deleteDocumentById` given no `trx`, which owns its own transaction. A lock wait timeout (errno 1205) is not
223
322
  retried.
224
323
 
225
324
  Only the outermost transaction retries. A call given an existing `trx`, or a