@jskit-ai/agent-docs 0.1.131 → 0.1.133

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 (171) hide show
  1. package/guide/agent/app-extras/assistant.md +29 -605
  2. package/guide/agent/app-extras/mobile-capacitor.md +29 -362
  3. package/guide/agent/app-extras/realtime.md +29 -277
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +44 -815
  5. package/guide/agent/app-setup/authentication.md +43 -1073
  6. package/guide/agent/app-setup/console.md +26 -298
  7. package/guide/agent/app-setup/database-layer.md +110 -790
  8. package/guide/agent/app-setup/existing-application-migration.md +273 -0
  9. package/guide/agent/app-setup/initial-scaffolding.md +50 -784
  10. package/guide/agent/app-setup/multi-homing.md +39 -712
  11. package/guide/agent/app-setup/quickstart.md +43 -179
  12. package/guide/agent/app-setup/users.md +34 -353
  13. package/guide/agent/index.md +17 -23
  14. package/package.json +2 -2
  15. package/patterns/INDEX.md +7 -7
  16. package/patterns/child-cruds.md +3 -3
  17. package/patterns/client-requests.md +6 -6
  18. package/patterns/crud-authoring.md +94 -0
  19. package/patterns/crud-links.md +1 -1
  20. package/patterns/feature-package/PATTERN.md +108 -0
  21. package/patterns/feature-package/example/booking-engine/package.json +48 -0
  22. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
  23. package/patterns/feature-package/example/booking-engine/src/server/actions.js +26 -0
  24. package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
  25. package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
  26. package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
  27. package/patterns/feature-package/example/variations/customKnexRepository.js +34 -0
  28. package/patterns/feature-package/example/variations/orchestratorService.js +23 -0
  29. package/patterns/filters.md +8 -8
  30. package/patterns/live-actions.md +5 -18
  31. package/patterns/minimal-foundation/PATTERN.md +98 -0
  32. package/patterns/minimal-foundation/example/.nvmrc +1 -0
  33. package/patterns/minimal-foundation/example/AGENTS.md +17 -0
  34. package/patterns/minimal-foundation/example/Procfile +2 -0
  35. package/patterns/minimal-foundation/example/app.json +14 -0
  36. package/patterns/minimal-foundation/example/bin/develop.js +71 -0
  37. package/patterns/minimal-foundation/example/bin/server.js +8 -0
  38. package/patterns/minimal-foundation/example/config/public.js +40 -0
  39. package/patterns/minimal-foundation/example/config/server.js +1 -0
  40. package/patterns/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
  41. package/patterns/minimal-foundation/example/eslint.config.mjs +19 -0
  42. package/patterns/minimal-foundation/example/favicon.svg +7 -0
  43. package/patterns/minimal-foundation/example/gitignore +9 -0
  44. package/patterns/minimal-foundation/example/index.html +13 -0
  45. package/patterns/minimal-foundation/example/jsconfig.json +8 -0
  46. package/patterns/minimal-foundation/example/package.json +57 -0
  47. package/patterns/minimal-foundation/example/packages/main/package.json +42 -0
  48. package/patterns/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
  49. package/patterns/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  50. package/patterns/minimal-foundation/example/playwright.config.mjs +31 -0
  51. package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
  52. package/patterns/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
  53. package/patterns/minimal-foundation/example/server.js +195 -0
  54. package/patterns/minimal-foundation/example/src/App.vue +13 -0
  55. package/patterns/minimal-foundation/example/src/main.js +85 -0
  56. package/patterns/minimal-foundation/example/src/pages/home/index.vue +48 -0
  57. package/patterns/minimal-foundation/example/src/pages/home.vue +13 -0
  58. package/patterns/minimal-foundation/example/src/views/NotFound.vue +13 -0
  59. package/patterns/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
  60. package/patterns/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  61. package/patterns/minimal-foundation/example/tests/server/smoke.test.js +16 -0
  62. package/patterns/minimal-foundation/example/vite.config.mjs +81 -0
  63. package/patterns/page-scaffolding.md +20 -17
  64. package/patterns/placements.md +17 -15
  65. package/patterns/row-policies.md +4 -5
  66. package/patterns/server-search.md +3 -3
  67. package/patterns/shell-foundation/PATTERN.md +104 -0
  68. package/patterns/shell-foundation/example/.nvmrc +1 -0
  69. package/patterns/shell-foundation/example/AGENTS.md +17 -0
  70. package/patterns/shell-foundation/example/Procfile +2 -0
  71. package/patterns/shell-foundation/example/app.json +14 -0
  72. package/patterns/shell-foundation/example/bin/develop.js +71 -0
  73. package/patterns/shell-foundation/example/bin/server.js +8 -0
  74. package/patterns/shell-foundation/example/config/public.js +40 -0
  75. package/patterns/shell-foundation/example/config/server.js +1 -0
  76. package/patterns/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
  77. package/patterns/shell-foundation/example/eslint.config.mjs +19 -0
  78. package/patterns/shell-foundation/example/favicon.svg +7 -0
  79. package/patterns/shell-foundation/example/gitignore +9 -0
  80. package/patterns/shell-foundation/example/index.html +13 -0
  81. package/patterns/shell-foundation/example/jsconfig.json +8 -0
  82. package/patterns/shell-foundation/example/package.json +59 -0
  83. package/patterns/shell-foundation/example/packages/main/package.json +56 -0
  84. package/patterns/shell-foundation/example/packages/main/src/client/index.js +9 -0
  85. package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
  86. package/patterns/shell-foundation/example/packages/main/src/shared/index.js +10 -0
  87. package/patterns/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  88. package/patterns/shell-foundation/example/playwright.config.mjs +31 -0
  89. package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
  90. package/patterns/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
  91. package/patterns/shell-foundation/example/server.js +195 -0
  92. package/patterns/shell-foundation/example/src/App.vue +11 -0
  93. package/patterns/shell-foundation/example/src/components/ShellLayout.vue +12 -0
  94. package/patterns/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
  95. package/patterns/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
  96. package/patterns/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
  97. package/patterns/shell-foundation/example/src/error.js +19 -0
  98. package/patterns/shell-foundation/example/src/main.js +85 -0
  99. package/patterns/shell-foundation/example/src/pages/home/index.vue +116 -0
  100. package/patterns/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
  101. package/patterns/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
  102. package/patterns/shell-foundation/example/src/pages/home/settings.vue +109 -0
  103. package/patterns/shell-foundation/example/src/pages/home.vue +20 -0
  104. package/patterns/shell-foundation/example/src/placement.js +56 -0
  105. package/patterns/shell-foundation/example/src/placementTopology.js +149 -0
  106. package/patterns/shell-foundation/example/src/views/NotFound.vue +13 -0
  107. package/patterns/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
  108. package/patterns/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
  109. package/patterns/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  110. package/patterns/shell-foundation/example/tests/server/smoke.test.js +16 -0
  111. package/patterns/shell-foundation/example/vite.config.mjs +81 -0
  112. package/patterns/ui-contract.md +56 -0
  113. package/patterns/ui-testing.md +10 -12
  114. package/reference/autogen/KERNEL_MAP.md +29 -107
  115. package/reference/autogen/PATTERN_INDEX.md +230 -0
  116. package/reference/autogen/README.md +4 -8
  117. package/reference/autogen/packages/agent-docs.md +259 -0
  118. package/reference/autogen/packages/assistant-core.md +3 -3
  119. package/reference/autogen/packages/assistant-runtime.md +32 -17
  120. package/reference/autogen/packages/auth-core.md +31 -33
  121. package/reference/autogen/packages/auth-provider-local-core.md +4 -12
  122. package/reference/autogen/packages/auth-provider-local-db-core.md +4 -4
  123. package/reference/autogen/packages/auth-provider-supabase-core.md +14 -18
  124. package/reference/autogen/packages/auth-web.md +42 -22
  125. package/reference/autogen/packages/console-core.md +8 -25
  126. package/reference/autogen/packages/console-web.md +5 -5
  127. package/reference/autogen/packages/crud-core.md +61 -17
  128. package/reference/autogen/packages/database-runtime-mysql.md +12 -2
  129. package/reference/autogen/packages/database-runtime-postgres.md +12 -2
  130. package/reference/autogen/packages/database-runtime.md +26 -25
  131. package/reference/autogen/packages/google-rewarded-core.md +19 -104
  132. package/reference/autogen/packages/http-runtime.md +4 -8
  133. package/reference/autogen/packages/http-web.md +32 -0
  134. package/reference/autogen/packages/json-rest-api-core.md +4 -6
  135. package/reference/autogen/packages/kernel.md +109 -390
  136. package/reference/autogen/packages/mobile-capacitor.md +2 -13
  137. package/reference/autogen/packages/realtime.md +29 -26
  138. package/reference/autogen/packages/resource-crud-core.md +6 -0
  139. package/reference/autogen/packages/shell-web.md +69 -54
  140. package/reference/autogen/packages/storage-runtime.md +3 -3
  141. package/reference/autogen/packages/uploads-image-web.md +0 -1
  142. package/reference/autogen/packages/uploads-runtime.md +3 -3
  143. package/reference/autogen/packages/users-core.md +45 -90
  144. package/reference/autogen/packages/users-web.md +5 -7
  145. package/reference/autogen/packages/workspaces-core.md +53 -74
  146. package/reference/autogen/packages/workspaces-web.md +15 -16
  147. package/reference/autogen/tooling/jskit-catalog.md +34 -0
  148. package/reference/autogen/tooling/testUtils.md +4 -4
  149. package/skills/jskit/SKILL.md +38 -31
  150. package/skills/jskit/references/app-operations.md +68 -53
  151. package/skills/jskit/references/crud-operations.md +58 -106
  152. package/skills/jskit/references/material-3.md +1 -1
  153. package/skills/jskit/references/ui-operations.md +41 -44
  154. package/templates/app/AGENTS.md +7 -3
  155. package/guide/agent/app-setup/upgrade-beta-1-to-final.md +0 -252
  156. package/guide/agent/app-setup/working-with-the-jskit-cli.md +0 -325
  157. package/guide/agent/generators/advanced-cruds.md +0 -1935
  158. package/guide/agent/generators/crud-generators.md +0 -948
  159. package/guide/agent/generators/intro.md +0 -65
  160. package/guide/agent/generators/row-policies.md +0 -537
  161. package/guide/agent/generators/ui-generators.md +0 -690
  162. package/patterns/crud-scaffolding.md +0 -198
  163. package/patterns/generated-ui-contract-tracking.md +0 -66
  164. package/reference/autogen/packages/assistant.md +0 -68
  165. package/reference/autogen/packages/crud-server-generator.md +0 -215
  166. package/reference/autogen/packages/crud-ui-generator.md +0 -192
  167. package/reference/autogen/packages/feature-server-generator.md +0 -65
  168. package/reference/autogen/packages/ui-generator.md +0 -127
  169. package/reference/autogen/tooling/create-app.md +0 -317
  170. package/reference/autogen/tooling/jskit-cli.md +0 -933
  171. package/reference/autogen/tooling/test-support.md +0 -27
@@ -2,623 +2,47 @@
2
2
 
3
3
  # Assistant
4
4
 
5
- At the end of the previous chapter, the app could already host live transports, but it still had no assistant surface of its own.
6
-
7
- Assistant setup in JSKIT happens in two layers:
8
-
9
- - `assistant-runtime`
10
- - the real runtime package
11
- - owns the shared tables, routes, client runtime, and config registries
12
- - `assistant`
13
- - a generator package used through `npx jskit generate assistant ...`
14
- - scaffolds pages and writes per-surface assistant configuration
15
-
16
- That split is the main thing to understand before you start. Installing the runtime does **not** automatically create assistant pages. The generator commands decide which surfaces get assistants and where each assistant is configured.
17
-
18
- In this chapter, we set up three assistants with three different roles:
19
-
20
- - a `console` assistant configured in `console`
21
- - an `admin` assistant configured from `console`
22
- - an `app` assistant configured from `admin`, with one configuration per workspace
23
-
24
- ## Installing `assistant-runtime`
25
-
26
- From inside `exampleapp`, run:
5
+ `@jskit-ai/assistant-runtime` supplies a reusable assistant runtime, client
6
+ elements, actions, persistence, and settings behavior. The application decides
7
+ where an assistant belongs and composes its pages directly.
27
8
 
28
9
  ```bash
29
- npx jskit add package assistant-runtime
10
+ npm install @jskit-ai/assistant-runtime
30
11
  npm run db:migrate
31
12
  ```
32
13
 
33
- This chapter needs the migration step because `assistant-runtime` installs real schema files for:
34
-
35
- - assistant configuration
36
- - assistant transcripts
37
-
38
- After this install, the app has the shared runtime pieces, but it still does **not** have any assistant pages. That is the next step.
39
-
40
- ## Three ideas you need before running the generator
41
-
42
- The assistant generator revolves around three separate ideas:
43
-
44
- - **runtime surface**
45
- - where the assistant chat UI actually lives
46
- - **settings surface**
47
- - where the assistant settings screen lives
48
- - **config scope**
49
- - whether the assistant settings are shared globally or stored per workspace
50
-
51
- Those are not the same thing.
52
-
53
- The assistant UI can live on one surface while its settings UI lives somewhere else. That is exactly what we want in this chapter.
54
-
55
- Here is the target shape:
56
-
57
- | Assistant runtime | Runtime surface | Settings surface | Config scope | Meaning |
58
- | --- | --- | --- | --- | --- |
59
- | Console assistant | `console` | `console` | `global` | One operator assistant for the whole app, configured in the operator surface itself |
60
- | Admin assistant | `admin` | `console` | `global` | Workspace-admin assistant UI, but centrally configured by app operators |
61
- | App assistant | `app` | `admin` | `workspace` | Member-facing assistant, configured per workspace from that workspace's admin settings |
62
-
63
- That table is the heart of the chapter.
64
-
65
- JSKIT is not forcing every assistant to be configured where it runs. It lets you choose the governance model that fits the surface.
66
-
67
- ## Registering the three assistant surfaces
68
-
69
- Set an AI key in your shell first if you already have one:
70
-
71
- ```bash
72
- OPENAI_API_KEY=...
73
- ```
74
-
75
- Then run:
76
-
77
- ```bash
78
- npx jskit generate assistant setup \
79
- --surface console \
80
- --settings-surface console \
81
- --config-scope global \
82
- --ai-provider openai \
83
- --ai-api-key "$OPENAI_API_KEY"
84
-
85
- npx jskit generate assistant setup \
86
- --surface admin \
87
- --settings-surface console \
88
- --config-scope global \
89
- --ai-provider openai \
90
- --ai-api-key "$OPENAI_API_KEY"
91
-
92
- npx jskit generate assistant setup \
93
- --surface app \
94
- --settings-surface admin \
95
- --config-scope workspace \
96
- --ai-provider openai \
97
- --ai-api-key "$OPENAI_API_KEY"
98
- ```
99
-
100
- These commands do **not** create any pages yet. They only register three assistant runtime surfaces and write their config blocks into the app.
101
-
102
- You can also leave `--ai-api-key` empty if you want to scaffold everything first and wire the key into `.env` later. The assistant pages will still exist, but the actual AI calls will stay unusable until the key is set.
103
-
104
- The important `setup` options are:
105
-
106
- - `--surface`
107
- - the runtime surface that will host the assistant UI
108
- - `--settings-surface`
109
- - the surface that will host the assistant settings screen
110
- - `--config-scope`
111
- - `global` or `workspace`
112
- - `--ai-provider`
113
- - which AI backend family this assistant surface should use
114
- - `--ai-api-key`
115
- - the API key for that assistant surface
116
- - `--ai-base-url`
117
- - an optional provider-compatible endpoint override
118
- - `--ai-timeout-ms`
119
- - the request timeout for that assistant surface
120
- - `--ai-config-prefix`
121
- - an optional override for the env/config prefix
122
- - if you omit it, JSKIT derives a prefix such as `CONSOLE_ASSISTANT` or `APP_ASSISTANT`
123
-
124
- **Important: Workspace Scope Needs Workspace Surfaces**
125
-
126
- `--config-scope workspace` only works when **both** of these surfaces require a workspace:
127
-
128
- - the runtime surface
129
- - the settings surface
130
-
131
- That is why the chapter uses:
132
-
133
- - `app` configured from `admin` with `workspace`
134
-
135
- but keeps:
136
-
137
- - `admin` configured from `console` with `global`
138
-
139
- `console` is a global surface. It does not carry a workspace slug, so it cannot host a workspace-scoped assistant settings flow.
140
-
141
- ## How assistant tools actually work
142
-
143
- This is the most important conceptual point in the whole assistant stack:
144
-
145
- The assistant does **not** automatically get access to "the backend" or to "all permission-guarded actions."
146
-
147
- What it really gets is a filtered **tool catalog** built from normal JSKIT actions.
148
-
149
- For an action to become an assistant tool, all of these must be true:
150
-
151
- - it is registered as a real JSKIT action
152
- - its `channels` include `"automation"`
153
- - it has both an input schema and an output schema
154
- - it is allowed on the current surface
155
- - the current actor is allowed to execute it
156
- - it is not hidden by the assistant surface config
157
-
158
- So the assistant is never discovering methods by reflection and it is never seeing the entire service layer. It only sees a deliberate action-backed contract.
159
-
160
- ### Making an action available to the assistant
161
-
162
- The normal pattern is:
163
-
164
- 1. define a normal JSKIT action
165
- 2. put it on the `automation` channel
166
- 3. give it real input and output schemas
167
- 4. optionally give it a better assistant-facing description
168
-
169
- For example:
170
-
171
- ```js
172
- {
173
- id: "workspace.members.invite",
174
- domain: "workspace",
175
- version: 1,
176
- kind: "command",
177
- channels: ["automation"],
178
- surfaces: ["admin"],
179
- permission: {
180
- require: "all",
181
- permissions: ["workspace.members.invite"]
182
- },
183
- input: {
184
- schema: {
185
- type: "object",
186
- properties: {
187
- email: { type: "string" }
188
- },
189
- required: ["email"],
190
- additionalProperties: false
191
- }
192
- },
193
- output: {
194
- schema: {
195
- type: "object",
196
- properties: {
197
- ok: { type: "boolean" }
198
- },
199
- required: ["ok"],
200
- additionalProperties: false
201
- }
202
- },
203
- extensions: {
204
- assistant: {
205
- description: "Invite a member into the current workspace."
206
- }
207
- }
208
- }
209
- ```
210
-
211
- That does two things at once:
212
-
213
- - it stays a normal JSKIT action
214
- - it becomes eligible for assistant exposure
215
-
216
- If you leave out `channels: ["automation"]`, the assistant will not see it.
217
-
218
- If you leave out the schemas, the assistant will not see it.
219
-
220
- So the assistant layer is intentionally strict. It only exposes actions with a stable machine-readable contract.
221
-
222
- ### Permissions still matter
223
-
224
- This is the next crucial point:
225
-
226
- The assistant only sees tools that the current actor could execute normally.
227
-
228
- So if an action says:
229
-
230
- ```js
231
- permission: {
232
- require: "all",
233
- permissions: ["workspace.members.invite"]
234
- }
235
- ```
236
-
237
- then a user who does **not** have `workspace.members.invite` does not merely get a later failure dialog. That tool is filtered out of the assistant's available tool list before the request is sent to the model.
238
-
239
- That means two users on the same surface can get different assistant capabilities, because their permission sets are different.
240
-
241
- This is an important mental model:
242
-
243
- - normal action permissions still remain the source of truth
244
- - the assistant is a client of that action system, not a bypass around it
245
-
246
- ### Surface rules still matter too
247
-
248
- Actions can also be restricted to specific surfaces.
249
-
250
- If an action only lists:
251
-
252
- ```js
253
- surfaces: ["admin"]
254
- ```
255
-
256
- then it can appear in the `admin` assistant but not in the `console` assistant or the `app` assistant.
257
-
258
- So tool exposure is filtered by **both**:
259
-
260
- - who the user is
261
- - where the assistant is running
262
-
263
- That is exactly why this chapter's three-assistant setup is interesting. The three assistants can share some actions but differ on others because they do not all run on the same surface.
264
-
265
- ### How to hide actions even if they qualify
266
-
267
- There is one more layer on top of action metadata.
268
-
269
- Per-surface assistant server config can still hide tools intentionally.
270
-
271
- The relevant config keys are:
272
-
273
- - `barredActionIds`
274
- - `toolSkipActionPrefixes`
275
-
276
- For example:
277
-
278
- ```js
279
- config.assistantServer.admin = {
280
- aiConfigPrefix: "ADMIN_ASSISTANT",
281
- barredActionIds: ["workspace.members.remove"],
282
- toolSkipActionPrefixes: ["workspace.audit."]
283
- };
284
- ```
285
-
286
- That means:
287
-
288
- - `workspace.members.remove` is hidden exactly
289
- - any action whose id starts with `workspace.audit.` is hidden by prefix
290
-
291
- This is useful when an action is valid in the app but you still do not want a given assistant surface to use it.
292
-
293
- So the full exposure model is:
294
-
295
- - action metadata says what *can* be a tool
296
- - permission and surface context say what this user *may* use now
297
- - assistant surface config says what this assistant surface *should still hide*
298
-
299
- ### How the assistant "knows" what it can do
300
-
301
- The assistant runtime does not ask the model to invent tools on the fly.
302
-
303
- Instead, for each request it builds the filtered tool set for the current:
304
-
305
- - surface
306
- - actor
307
- - permission set
308
- - workspace context
309
-
310
- Then it sends two things into the AI request:
311
-
312
- - the tool schemas themselves
313
- - a system-prompt summary of the available tool names and contracts
314
-
315
- So the model only sees the tools that survived all of the filtering above.
316
-
317
- If a tool is unavailable:
318
-
319
- - it is not described in the prompt
320
- - it is not included in the tool schema payload
321
-
322
- And even after that, actual execution still goes through the normal JSKIT action executor under the `automation` channel. So the assistant is constrained twice:
323
-
324
- - first by tool-catalog filtering
325
- - then by real action execution
326
-
327
- ### Workspace context is handled for you
328
-
329
- Workspace-scoped tools get one more convenience.
330
-
331
- If the current assistant is already running inside a workspace route, the tool catalog can hide the `workspaceSlug` field from the visible tool schema and inject it from the current request context during execution.
332
-
333
- That means a workspace assistant can expose simpler tools to the model:
334
-
335
- - "invite a member into the current workspace"
336
-
337
- instead of always forcing the tool contract to say:
338
-
339
- - "invite a member, and also provide the workspace slug again"
340
-
341
- That makes the assistant contracts cleaner without weakening the actual workspace boundary.
342
-
343
- ## Generating the assistant pages
344
-
345
- Now create the three runtime pages:
346
-
347
- ```bash
348
- npx jskit generate assistant page console/assistant/index.vue
349
-
350
- npx jskit generate assistant page \
351
- w/[workspaceSlug]/admin/assistant/index.vue \
352
- --name "Assistant"
353
-
354
- npx jskit generate assistant page \
355
- w/[workspaceSlug]/assistant/index.vue \
356
- --name "Assistant"
357
- ```
358
-
359
- These commands use the page path to decide where the assistant should live.
360
-
361
- That gives you:
362
-
363
- - `/console/assistant`
364
- - `/w/[workspaceSlug]/admin/assistant`
365
- - `/w/[workspaceSlug]/assistant`
366
-
367
- Each generated file is intentionally thin. For example:
368
-
369
- ```vue
370
- <template>
371
- <AssistantSurfaceClientElement surface-id="console" />
372
- </template>
373
-
374
- <script setup>
375
- import { AssistantSurfaceClientElement } from "@jskit-ai/assistant-runtime/client";
376
- </script>
377
- ```
378
-
379
- That is a good JSKIT pattern to notice:
380
-
381
- - the app owns the route file
382
- - the route file says which assistant surface it is exposing
383
- - the reusable runtime element owns the heavy client behavior
384
-
385
- The page generator also adds shell menu placements for those new routes, so the surfaces get real navigation entries without you hand-editing the menus.
386
-
387
- In the `page` subcommand:
388
-
389
- - the target file path decides the route location
390
- - `--name` changes the generated menu label
391
- - `--link-placement` and `--link-to` are optional overrides if you want to place the route link somewhere other than the generator's normal inferred semantic target
392
-
393
- ## Generating the assistant settings pages
394
-
395
- Now create the three settings pages:
396
-
397
- ```bash
398
- npx jskit generate assistant settings-page \
399
- console/settings/assistant/index.vue \
400
- --surface console
401
-
402
- npx jskit generate assistant settings-page \
403
- console/settings/admin-assistant/index.vue \
404
- --surface admin \
405
- --name "Admin Assistant"
406
-
407
- npx jskit generate assistant settings-page \
408
- w/[workspaceSlug]/admin/workspace/settings/app-assistant/index.vue \
409
- --surface app \
410
- --name "App Assistant"
411
- ```
412
-
413
- This is the part that often trips people up, so read the rule carefully:
414
-
415
- - the **target file path** decides where the settings page lives
416
- - `--surface` decides **which assistant runtime surface that page configures**
417
-
418
- So:
419
-
420
- - `/console/settings/admin-assistant` configures the `admin` assistant
421
- - `/w/[workspaceSlug]/admin/workspace/settings/app-assistant` configures the `app` assistant
422
-
423
- That is not contradictory. It is the whole point of the design.
424
-
425
- The generated settings pages are also thin wrappers:
426
-
427
- ```vue
428
- <template>
429
- <AssistantSettingsClientElement target-surface-id="app" />
430
- </template>
431
-
432
- <script setup>
433
- import { AssistantSettingsClientElement } from "@jskit-ai/assistant-runtime/client";
434
- </script>
435
- ```
436
-
437
- The file path decides where the settings screen is opened. `target-surface-id` decides which assistant it edits.
438
-
439
- The inferred placement matters here too:
440
-
441
- - `--name`
442
- - the label shown for the settings entry
443
-
444
- The console settings pages live under the console settings host, so JSKIT infers `page.section-nav` with owner `console-settings`. The workspace settings page lives under the admin workspace settings host, so JSKIT infers `page.section-nav` with owner `admin-settings`.
445
-
446
- The concrete outlet and link renderer come from topology. Those settings hosts map `page.section-nav` to their concrete menus in `src/placementTopology.js`, so the commands do not need renderer flags.
447
-
448
- ## What to look at in the browser
449
-
450
- Start both processes again:
451
-
452
- ```bash
453
- npm run dev
454
- npm run server
455
- ```
456
-
457
- After sign-in, the app should expose these assistant routes:
458
-
459
- - `/console/assistant`
460
- - `/w/your-personal-slug/admin/assistant`
461
- - `/w/your-personal-slug/assistant`
462
-
463
- And these settings routes:
464
-
465
- - `/console/settings/assistant`
466
- - `/console/settings/admin-assistant`
467
- - `/w/your-personal-slug/admin/workspace/settings/app-assistant`
468
-
469
- The most important thing to verify in the browser is the *relationship* between those pages.
470
-
471
- - The `console` assistant runs in `console` and is configured in `console`.
472
- - The `admin` assistant runs in the workspace `admin` surface, but its settings live in `console`, because this chapter treats it as centrally governed.
473
- - The `app` assistant runs in the workspace `app` surface, and its settings live in workspace `admin`, because this chapter treats it as a workspace-owned assistant.
474
-
475
- That gives the app two different governance models at the same time:
476
-
477
- - app-wide operator-owned assistant config
478
- - per-workspace assistant config
479
-
480
- If you left the AI key empty, the pages and settings screens will still exist, but the assistant itself will not become useful until the AI key is filled into `.env`.
481
-
482
- ## What `assistant-runtime` and `assistant` add to the app
483
-
484
- This chapter changes more files than the realtime chapter, but the changes are still easy to read if you keep the runtime/generator split in mind.
485
-
486
- ### `config/public.js` maps assistant runtime surfaces
487
-
488
- After the three `setup` commands, `config/public.js` contains:
489
-
490
- ```js
491
- config.assistantSurfaces.console = {
492
- settingsSurfaceId: "console",
493
- configScope: "global"
494
- };
495
-
496
- config.assistantSurfaces.admin = {
497
- settingsSurfaceId: "console",
498
- configScope: "global"
499
- };
500
-
501
- config.assistantSurfaces.app = {
502
- settingsSurfaceId: "admin",
503
- configScope: "workspace"
504
- };
505
- ```
506
-
507
- This is the public routing contract for assistants.
508
-
509
- For each assistant runtime surface, it answers:
510
-
511
- - where is this assistant configured?
512
- - is that configuration global or workspace-specific?
513
-
514
- ### `config/server.js` chooses the env/config prefix for each assistant
515
-
516
- The same `setup` commands also write:
517
-
518
- ```js
519
- config.assistantServer.console = {
520
- aiConfigPrefix: "CONSOLE_ASSISTANT"
521
- };
522
-
523
- config.assistantServer.admin = {
524
- aiConfigPrefix: "ADMIN_ASSISTANT"
525
- };
526
-
527
- config.assistantServer.app = {
528
- aiConfigPrefix: "APP_ASSISTANT"
529
- };
530
- ```
531
-
532
- That is what lets one app host several assistants at once without their AI settings colliding.
533
-
534
- ### `.env` gains one AI block per assistant surface
535
-
536
- The app gets env keys such as:
537
-
538
- ```dotenv
539
- CONSOLE_ASSISTANT_AI_PROVIDER=openai
540
- CONSOLE_ASSISTANT_AI_API_KEY=
541
- CONSOLE_ASSISTANT_AI_BASE_URL=
542
- CONSOLE_ASSISTANT_AI_TIMEOUT_MS=120000
543
-
544
- ADMIN_ASSISTANT_AI_PROVIDER=openai
545
- ADMIN_ASSISTANT_AI_API_KEY=
546
- ADMIN_ASSISTANT_AI_BASE_URL=
547
- ADMIN_ASSISTANT_AI_TIMEOUT_MS=120000
548
-
549
- APP_ASSISTANT_AI_PROVIDER=openai
550
- APP_ASSISTANT_AI_API_KEY=
551
- APP_ASSISTANT_AI_BASE_URL=
552
- APP_ASSISTANT_AI_TIMEOUT_MS=120000
553
- ```
554
-
555
- That is why `setup` is a per-surface command. Each assistant runtime surface gets its own AI configuration namespace.
556
-
557
- ### `migrations/` gains assistant schema files
558
-
559
- Installing `assistant-runtime` also adds schema files for:
560
-
561
- - assistant configuration
562
- - assistant transcripts
563
-
564
- Those are shared runtime tables. The generator does not create them. That is the runtime package's job.
565
-
566
- ### `src/pages/...` gains thin runtime and settings wrappers
567
-
568
- After the chapter, the app owns several new route files under `src/pages/...`.
569
-
570
- The important point is that they are all small wrappers around reusable client elements:
571
-
572
- - runtime pages use `AssistantSurfaceClientElement`
573
- - settings pages use `AssistantSettingsClientElement`
574
-
575
- That keeps the app-owned routing explicit without copying the runtime logic into every page file.
576
-
577
- ### `src/placement.js` grows assistant links in several menus
578
-
579
- The page generator and settings-page generator also append placement entries.
580
-
581
- That is how the assistant routes show up in:
582
-
583
- - the main shell menus for `console`, `admin`, and `app`
584
- - the `console` settings menu
585
- - the workspace `admin` settings menu
586
-
587
- So the generator is not only creating route files. It is also wiring those routes into the right existing shell and settings outlets.
588
-
589
- ## Under the hood
590
-
591
- `assistant-runtime` owns the shared assistant engine:
592
-
593
- - server routes
594
- - database tables
595
- - client runtime
596
- - config loading for each assistant surface
14
+ Use the `assistant/assistant-surface` pattern. There is no assistant generator.
597
15
 
598
- The `assistant` generator then writes the app-specific shape around that engine:
16
+ ## Product decisions
599
17
 
600
- - which assistant surfaces exist
601
- - where their runtime pages live
602
- - where their settings pages live
603
- - which menu outlets should link to them
18
+ Choose:
604
19
 
605
- The runtime uses the current surface and, when needed, the current workspace route context to resolve the right assistant configuration.
20
+ - the runtime surface and settings surface;
21
+ - global or workspace configuration scope;
22
+ - page routes and placement roles;
23
+ - provider and model policy;
24
+ - whether the assistant begins disabled until credentials exist.
606
25
 
607
- That is also why impossible combinations are rejected early. If you ask for workspace-scoped settings on a non-workspace surface, JSKIT fails at generation time instead of letting the app drift into a broken setup.
26
+ The application records an environment prefix, never an API key, in source.
27
+ Secrets arrive through the normal deployment or development environment.
608
28
 
609
- ## Summary
29
+ ## Composition
610
30
 
611
- This chapter adds a lot of capability without inventing a new monolithic "assistant mode."
31
+ Use `AssistantSurfaceClientElement` and
32
+ `AssistantSettingsClientElement` from `@jskit-ai/assistant-runtime/client`.
33
+ Configure public surface behavior and server settings in ordinary app-owned
34
+ config, then register routes and placements like any other feature.
612
35
 
613
- - `assistant-runtime` installs the shared assistant engine
614
- - `assistant setup` registers one assistant runtime surface at a time
615
- - `assistant page` decides where each assistant UI lives
616
- - `assistant settings-page` decides where each assistant is configured
36
+ Workspace scope is valid only when both the runtime and its settings surface
37
+ are workspace-aware. Requests must retain the selected workspace through the
38
+ server action boundary.
617
39
 
618
- By the end of the chapter, the app has:
40
+ ## Verification
619
41
 
620
- - one global operator assistant in `console`
621
- - one workspace-admin assistant governed from `console`
622
- - one workspace-facing assistant governed from `admin`
42
+ Run migrations, load assistant and settings pages through normal navigation,
43
+ test missing credentials without exposing values, exercise one successful and
44
+ one provider-error conversation, and verify global or cross-workspace isolation.
623
45
 
624
- That is a good example of JSKIT's surface model paying off. The assistant is not tied to one hard-coded area of the app. It can live and be governed differently on different surfaces.
46
+ Do not add a second model client beside the runtime, copy its repositories or
47
+ routes, infer a surface, store keys in source, or keep generator markers,
48
+ questionnaire answers, receipts, or provenance.