@jskit-ai/agent-docs 0.1.26 → 0.1.28

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 (46) hide show
  1. package/DISTR_AGENT.md +1 -0
  2. package/guide/agent/app-extras/assistant.md +9 -20
  3. package/guide/agent/app-extras/mobile-capacitor.md +381 -0
  4. package/guide/agent/app-extras/realtime.md +13 -12
  5. package/guide/agent/app-setup/a-more-interesting-shell.md +102 -87
  6. package/guide/agent/app-setup/authentication.md +50 -31
  7. package/guide/agent/app-setup/console.md +8 -8
  8. package/guide/agent/app-setup/database-layer.md +15 -15
  9. package/guide/agent/app-setup/initial-scaffolding.md +37 -5
  10. package/guide/agent/app-setup/multi-homing.md +50 -47
  11. package/guide/agent/app-setup/quickstart.md +11 -14
  12. package/guide/agent/app-setup/users.md +24 -24
  13. package/guide/agent/app-setup/working-with-the-jskit-cli.md +18 -10
  14. package/guide/agent/generators/advanced-cruds.md +111 -68
  15. package/guide/agent/generators/crud-generators.md +5 -5
  16. package/guide/agent/generators/ui-generators.md +44 -36
  17. package/guide/agent/index.md +3 -2
  18. package/package.json +1 -1
  19. package/patterns/INDEX.md +4 -1
  20. package/patterns/client-requests.md +23 -6
  21. package/patterns/crud-repository-mapping.md +1 -1
  22. package/patterns/crud-scaffolding.md +10 -1
  23. package/patterns/filters.md +28 -10
  24. package/patterns/generated-ui-contract-tracking.md +62 -0
  25. package/patterns/page-scaffolding.md +20 -2
  26. package/patterns/placements.md +67 -1
  27. package/patterns/surfaces.md +5 -1
  28. package/patterns/ui-testing.md +3 -0
  29. package/reference/autogen/KERNEL_MAP.md +46 -1
  30. package/reference/autogen/README.md +3 -0
  31. package/reference/autogen/packages/assistant.md +2 -1
  32. package/reference/autogen/packages/auth-web.md +20 -1
  33. package/reference/autogen/packages/crud-ui-generator.md +20 -8
  34. package/reference/autogen/packages/google-rewarded-core.md +222 -0
  35. package/reference/autogen/packages/google-rewarded-web.md +71 -0
  36. package/reference/autogen/packages/kernel.md +94 -10
  37. package/reference/autogen/packages/mobile-capacitor.md +76 -0
  38. package/reference/autogen/packages/realtime.md +1 -0
  39. package/reference/autogen/packages/shell-web.md +48 -3
  40. package/reference/autogen/packages/ui-generator.md +34 -2
  41. package/reference/autogen/packages/users-core.md +2 -0
  42. package/reference/autogen/packages/users-web.md +92 -4
  43. package/reference/autogen/packages/workspaces-web.md +3 -2
  44. package/reference/autogen/tooling/jskit-cli.md +114 -9
  45. package/templates/app/AGENTS.md +1 -0
  46. package/workflow/bootstrap.md +1 -0
@@ -63,7 +63,7 @@ npx jskit show @jskit-ai/workspaces-web --details
63
63
 
64
64
  That output makes the package feel much less mysterious, because it shows the exact workspace shell contributions, settings outlets, client tokens, app-owned file writes, and capability requirements before you mutate the app.
65
65
 
66
- ## What changes now
66
+ ## What workspaces add
67
67
 
68
68
  This chapter is where the app stops being a collection of global surfaces and starts supporting workspace-dependent ones.
69
69
 
@@ -107,13 +107,13 @@ That is why this chapter feels larger than the previous ones. It is not just add
107
107
 
108
108
  ### The shell and account surface gain workspace-aware controls
109
109
 
110
- The placement registry now grows a workspace selector in the top-left of the shell, a pending-invites cue in the top-right area, and workspace tools in the admin shell. The workspaces package also plugs an `Invites` section into the existing `/account` settings screen through the account-settings extension seam that `users-web` exposes.
110
+ The placement registry gets a workspace selector in `shell.identity`, pending-invites and workspace tools in `shell.status`, and an `Invites` section in the existing `/account` settings screen through the account-settings extension seam that `users-web` exposes. The default shell topology maps identity/status placements to the visible shell chrome.
111
111
 
112
112
  That means the shell itself starts adapting to workspace context.
113
113
 
114
- - on any authenticated surface, the shell can now expose a workspace selector
115
- - signed-in users can now see a pending-invites cue without `users-web` owning that workspace feature
116
- - on admin workspace surfaces, the shell can also expose workspace-specific tools and settings
114
+ - on any authenticated surface, the shell can expose a workspace selector
115
+ - signed-in users can see a pending-invites cue without `users-web` owning that workspace feature
116
+ - on admin workspace surfaces, the shell can expose workspace-specific tools and settings
117
117
 
118
118
  This is the first time the guide shows the shell reacting not just to authentication state, but to workspace state as well.
119
119
 
@@ -139,7 +139,7 @@ This is also important to notice:
139
139
 
140
140
  The new workspace surfaces are added on top of the existing app, not instead of it.
141
141
 
142
- That is exactly what multi-homing should feel like. The app now has both:
142
+ That is exactly what multi-homing should feel like. The app has both:
143
143
 
144
144
  - global surfaces
145
145
  - workspace-scoped surfaces
@@ -153,7 +153,7 @@ npm run dev
153
153
  npm run server
154
154
  ```
155
155
 
156
- After you sign in, the app now has the routing structure needed for workspace-aware paths such as:
156
+ After you sign in, the app has the routing structure needed for workspace-aware paths such as:
157
157
 
158
158
  ```text
159
159
  /w/your-personal-slug
@@ -166,15 +166,15 @@ At this stage of the guide, the starter workspace pages are still intentionally
166
166
 
167
167
  The most important new visible ideas are:
168
168
 
169
- - a workspace slug now appears in the route
169
+ - a workspace slug appears in the route
170
170
  - the shell can expose workspace selection and workspace tools
171
171
  - workspace-dependent surfaces can show a dedicated unavailable-state card when the requested workspace cannot be resolved
172
172
 
173
- First, even the old global `/home` surface now reacts to workspace state. The selector in the top-left and the invites cue in the top-right come from placement entries and workspace bootstrap context, not from the `home` page itself.
173
+ First, even the global `/home` surface reacts to workspace state. The selector and invites cue come from semantic placement entries and workspace bootstrap context, not from the `home` page itself.
174
174
 
175
- Then open your personal workspace route. The page itself is deliberately light. `src/pages/w/[workspaceSlug]/index.vue` mostly exists to prove that the `app` surface is now real and ready to host later modules.
175
+ Then open your personal workspace route. The page itself is deliberately light. `src/pages/w/[workspaceSlug]/index.vue` mostly exists to prove that the `app` surface is real and ready to host later modules.
176
176
 
177
- Next open the admin surface for the same workspace. This is the matching pattern on the admin side: `src/pages/w/[workspaceSlug]/admin.vue` is the shell wrapper, `src/pages/w/[workspaceSlug]/admin/index.vue` is the starter page, and the top-right workspace tools button is coming from placements rather than being hand-built into that page file.
177
+ Next open the admin surface for the same workspace. This is the matching pattern on the admin side: `src/pages/w/[workspaceSlug]/admin.vue` is the shell wrapper, `src/pages/w/[workspaceSlug]/admin/index.vue` is the starter page, and the workspace tools button is coming from placements rather than being hand-built into that page file.
178
178
 
179
179
  Finally open the nested workspace settings route. This is useful to inspect because it shows the container pattern most clearly. `src/pages/w/[workspaceSlug]/admin/workspace/settings.vue` owns the section frame and the child outlet, while the actual settings sub-pages can keep arriving later under that shell.
180
180
 
@@ -231,7 +231,7 @@ config.workspaceInvitations = {
231
231
  };
232
232
  ```
233
233
 
234
- Those lines are the public contract that tells both client and server, "this app is workspace-aware now."
234
+ Those lines are the public contract that tells both client and server that this app is workspace-aware.
235
235
 
236
236
  ### `config/surfaceAccessPolicies.js` gains `workspace_member`
237
237
 
@@ -252,7 +252,7 @@ That is the core idea of multi-homing in JSKIT:
252
252
  - the server resolves that workspace
253
253
  - access depends on whether the current user belongs to it
254
254
 
255
- ### The migrations now include workspace schema
255
+ ### The migrations include workspace schema
256
256
 
257
257
  After `workspaces-core`, the migration directory grows again with files such as:
258
258
 
@@ -269,7 +269,7 @@ That is why the chapter needs another `npm run db:migrate`. Without those tables
269
269
 
270
270
  ### The route tree gains workspace-dependent pages
271
271
 
272
- The app now gets:
272
+ The app gets:
273
273
 
274
274
  ```text
275
275
  src/pages/w/[workspaceSlug].vue
@@ -325,16 +325,13 @@ That command does two things:
325
325
  - it creates `src/pages/w/[workspaceSlug]/admin/workspace/settings/billing/index.vue`
326
326
  - it also appends the matching workspace settings menu entry into `src/placement.js`
327
327
 
328
- The reason JSKIT can wire that link automatically is that the workspace settings shell already exposes a named placement outlet with a default link renderer:
328
+ The reason JSKIT can wire that link automatically is that the workspace settings shell already exposes a concrete outlet and topology maps it to semantic section navigation:
329
329
 
330
330
  ```vue
331
- <ShellOutlet
332
- target="admin-settings:primary-menu"
333
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
334
- />
331
+ <ShellOutlet target="admin-settings:primary-menu" />
335
332
  ```
336
333
 
337
- `target="admin-settings:primary-menu"` tells the generator which settings menu host owns those child links. `default-link-component-token="local.main.ui.surface-aware-menu-link-item"` tells it which local menu-link component to use unless you override it. So a page generated under `w/[workspaceSlug]/admin/workspace/settings/...` automatically lands in the left-side workspace settings menu without you hand-writing the placement entry.
334
+ The route host lets the generator infer `page.section-nav` with owner `admin-settings`. `src/placementTopology.js` then maps that semantic placement to `admin-settings:primary-menu` and supplies the link renderer for compact, medium, and expanded layouts. So a page generated under `w/[workspaceSlug]/admin/workspace/settings/...` automatically lands in the left-side workspace settings menu without you hand-writing the placement entry.
338
335
 
339
336
  ### Workspace pages are prepared for missing-workspace states
340
337
 
@@ -524,7 +521,8 @@ The workspace packages append a new block of placements:
524
521
  ```js
525
522
  addPlacement({
526
523
  id: "workspaces.profile.menu.surface-switch",
527
- target: "auth-profile-menu:primary-menu",
524
+ target: "auth.profile-menu",
525
+ kind: "component",
528
526
  surfaces: ["*"],
529
527
  order: 100,
530
528
  componentToken: "workspaces.web.profile.menu.surface-switch-item",
@@ -533,7 +531,8 @@ addPlacement({
533
531
 
534
532
  addPlacement({
535
533
  id: "workspaces.workspace.selector",
536
- target: "shell-layout:top-left",
534
+ target: "shell.identity",
535
+ kind: "component",
537
536
  surfaces: ["*"],
538
537
  order: 200,
539
538
  componentToken: "workspaces.web.workspace.selector",
@@ -548,7 +547,8 @@ addPlacement({
548
547
 
549
548
  addPlacement({
550
549
  id: "workspaces.account.invites.cue",
551
- target: "shell-layout:top-right",
550
+ target: "shell.status",
551
+ kind: "component",
552
552
  surfaces: ["*"],
553
553
  order: 850,
554
554
  componentToken: "local.main.account.pending-invites.cue",
@@ -557,7 +557,8 @@ addPlacement({
557
557
 
558
558
  addPlacement({
559
559
  id: "workspaces.workspace.tools.widget",
560
- target: "shell-layout:top-right",
560
+ target: "shell.status",
561
+ kind: "component",
561
562
  surfaces: ["admin"],
562
563
  order: 900,
563
564
  componentToken: "workspaces.web.workspace.tools.widget"
@@ -565,7 +566,8 @@ addPlacement({
565
566
 
566
567
  addPlacement({
567
568
  id: "workspaces.workspace.menu.workspace-settings",
568
- target: "admin-cog:primary-menu",
569
+ target: "admin.tools-menu",
570
+ kind: "component",
569
571
  surfaces: ["admin"],
570
572
  order: 100,
571
573
  componentToken: "workspaces.web.workspace-settings.menu-item"
@@ -573,51 +575,52 @@ addPlacement({
573
575
 
574
576
  addPlacement({
575
577
  id: "workspaces.workspace.menu.members",
576
- target: "admin-cog:primary-menu",
578
+ target: "admin.tools-menu",
579
+ kind: "component",
577
580
  surfaces: ["admin"],
578
581
  order: 200,
579
582
  componentToken: "workspaces.web.workspace-members.menu-item"
580
583
  });
581
584
  ```
582
585
 
583
- That one block explains a lot of the new shell behavior.
586
+ That one block explains a lot of the workspace shell behavior.
584
587
 
585
- - the authenticated profile menu can now switch into workspace surfaces
586
- - the top-left area now has a workspace selector
587
- - the top-right area can show a pending-invites cue
588
- - the admin surface gets workspace tools in the top-right area
589
- - the admin workspace settings menu is now another nested placement host with both `Settings` and `Members`
588
+ - the authenticated profile menu can switch into workspace surfaces
589
+ - `shell.identity` carries the workspace selector
590
+ - `shell.status` can show a pending-invites cue
591
+ - the admin surface gets workspace tools through `shell.status`
592
+ - the admin workspace settings menu is another nested placement host with both `Settings` and `Members`
590
593
 
591
- If you want to add your own app-owned page into that top cog menu, first ask JSKIT which placement targets exist:
594
+ If you want to add your own app-owned page into that top cog menu, first ask JSKIT which semantic placements exist:
592
595
 
593
596
  ```bash
594
597
  npx jskit list-placements
595
598
  ```
596
599
 
597
- In a workspace-enabled app, that list now includes:
600
+ In a workspace-enabled app, that list includes:
598
601
 
599
602
  ```text
600
- - admin-cog:primary-menu [package:@jskit-ai/workspaces-web:src/client/components/UsersWorkspaceToolsWidget.vue]
603
+ - admin.tools-menu: Admin surface tools menu actions.
601
604
  ```
602
605
 
603
- If you want more context than the raw target list, `npx jskit show @jskit-ai/workspaces-web --details` also shows that same outlet plus the default `Settings` and `Members` entries already targeting it.
606
+ If you want the underlying outlet inventory, use `npx jskit list-placements --concrete`. If you want more package context, `npx jskit show @jskit-ai/workspaces-web --details` also shows the topology plus the default `Settings` and `Members` entries already targeting it.
604
607
 
605
- Once you know the outlet id, generate the page like this:
608
+ Once you know the semantic placement id, generate the page like this:
606
609
 
607
610
  ```bash
608
611
  npx jskit generate ui-generator page \
609
612
  w/[workspaceSlug]/admin/catalogue/index.vue \
610
613
  --name "Catalogue" \
611
- --link-placement admin-cog:primary-menu
614
+ --link-placement admin.tools-menu
612
615
  ```
613
616
 
614
617
  That command creates `src/pages/w/[workspaceSlug]/admin/catalogue/index.vue` and appends the matching link entry into `src/placement.js`.
615
618
 
616
- `--link-placement` is necessary here because this route is just a normal `admin` page. It is **not** a child page under a local host like `w/[workspaceSlug]/admin/workspace/settings.vue`, so the generator has no nested settings outlet to infer automatically. If you omit `--link-placement`, the new page link falls back to the app's default shell menu outlet instead of the cog menu.
619
+ `--link-placement` is necessary here because this route is just a normal `admin` page. It is **not** a child page under a local host like `w/[workspaceSlug]/admin/workspace/settings.vue`, so the generator has no nested settings placement to infer automatically. If you omit `--link-placement`, the new page link falls back to the app's default `shell.primary-nav` placement instead of the cog menu.
617
620
 
618
- You also do **not** need `--link-component-token` here. `admin-cog:primary-menu` already declares `local.main.ui.surface-aware-menu-link-item` as its default link renderer, so JSKIT reuses that automatically when it writes the placement entry.
621
+ You also do **not** need a renderer flag here. `admin.tools-menu` defines its link renderer in topology, so JSKIT resolves that when it renders the placement entry.
619
622
 
620
- So the placement system from the shell chapter is still doing the same job as before. The app just has a richer routing and tenancy context now.
623
+ So the placement system from the shell chapter is doing the same job with a richer routing and tenancy context.
621
624
 
622
625
  ### The local client provider gets one more app-owned token
623
626
 
@@ -663,7 +666,7 @@ registerProfileSyncLifecycleContributor(app, "workspaces.core.profileSyncLifecyc
663
666
 
664
667
  That means the workspace package does not need to patch auth directly to learn that a user was added. It listens through the `users-core` lifecycle registry instead.
665
668
 
666
- For this chapter's `tenancyMode = "personal"` setup, that contributor now does real work. When an authenticated JSKIT user is synchronized from auth, `workspaces-core` ensures that user's personal workspace exists.
669
+ For this chapter's `tenancyMode = "personal"` setup, that contributor does real work. When an authenticated JSKIT user is synchronized from auth, `workspaces-core` ensures that user's personal workspace exists.
667
670
 
668
671
  That detail matters for the retrofit path described earlier in this chapter. If the app started on `none`, then later switched to `personal`, the first sign-in after that switch still needs to backfill the personal workspace for the already-existing user record. The lifecycle contributor handles that because the workspace provision step is idempotent.
669
672
 
@@ -709,9 +712,9 @@ Before:
709
712
  After:
710
713
 
711
714
  - global surfaces still exist
712
- - workspace-scoped surfaces now exist too
715
+ - workspace-scoped surfaces exist too
713
716
  - the shell can navigate between workspaces
714
- - access to some surfaces now depends on workspace membership
717
+ - access to some surfaces depends on workspace membership
715
718
 
716
719
  That is why multi-homing deserves its own chapter. It is not just another feature package. It is the moment the app becomes tenancy-aware.
717
720
 
@@ -719,11 +722,11 @@ That is why multi-homing deserves its own chapter. It is not just another featur
719
722
 
720
723
  This chapter is the real routing and tenancy pivot in the guide.
721
724
 
722
- - the app now uses `tenancyMode = "personal"`
725
+ - the app uses `tenancyMode = "personal"`
723
726
  - `workspaces-core` added the persistent schema and server runtime for workspaces
724
727
  - `workspaces-web` added the first workspace-scoped surfaces, shell controls, and the workspace-owned account invites extension
725
728
 
726
- At the end of this chapter, the app now has both:
729
+ At the end of this chapter, the app has both:
727
730
 
728
731
  - global surfaces such as `home`, `auth`, `account`, and `console`
729
732
  - workspace-scoped surfaces such as `/w/[workspaceSlug]` and `/w/[workspaceSlug]/admin`
@@ -733,7 +736,7 @@ That is the most important mental shift to keep:
733
736
  - earlier chapters added features inside one global app shell
734
737
  - this chapter changed the topology of the app itself
735
738
 
736
- From here on, later modules are no longer only adding pages or widgets. They can add features inside either:
739
+ From here on, later modules can add features inside either:
737
740
 
738
741
  - the global surfaces
739
742
  - the workspace-specific surfaces
@@ -85,9 +85,7 @@ npx jskit generate assistant page \
85
85
  npx jskit generate assistant settings-page \
86
86
  console/settings/admin-assistant/index.vue \
87
87
  --surface admin \
88
- --name "Admin Assistant" \
89
- --link-placement console-settings:primary-menu \
90
- --link-component-token local.main.ui.surface-aware-menu-link-item
88
+ --name "Admin Assistant"
91
89
 
92
90
  npm install
93
91
  npm run db:migrate
@@ -154,7 +152,7 @@ First list the available placement destinations:
154
152
  npx jskit list-placements
155
153
  ```
156
154
 
157
- In a workspace-enabled app, that output includes `admin-cog:primary-menu`.
155
+ In a workspace-enabled app, that output includes the semantic `admin.tools-menu` placement.
158
156
 
159
157
  Then generate the page:
160
158
 
@@ -162,7 +160,7 @@ Then generate the page:
162
160
  npx jskit generate ui-generator page \
163
161
  w/[workspaceSlug]/admin/catalogue/index.vue \
164
162
  --name "Catalogue" \
165
- --link-placement admin-cog:primary-menu
163
+ --link-placement admin.tools-menu
166
164
  ```
167
165
 
168
166
  `--link-placement` is necessary here because this is just a normal `admin` page. It is not a child page under a local route host that already owns a nested outlet.
@@ -183,13 +181,10 @@ Because this page is not under a more specific local host, JSKIT falls back to t
183
181
 
184
182
  The workspace settings pages in Step 2 auto-linked into the settings menu for two reasons:
185
183
 
186
- 1. The parent host already exposes a named outlet:
184
+ 1. The parent host already exposes a concrete outlet:
187
185
 
188
186
  ```vue
189
- <ShellOutlet
190
- target="admin-settings:primary-menu"
191
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
192
- />
187
+ <ShellOutlet target="admin-settings:primary-menu" />
193
188
  ```
194
189
 
195
190
  2. Your generated pages live under that host route:
@@ -200,12 +195,14 @@ w/[workspaceSlug]/admin/workspace/settings/...
200
195
 
201
196
  So JSKIT can infer both:
202
197
 
203
- - the placement target: `admin-settings:primary-menu`
204
- - the default link renderer: `local.main.ui.surface-aware-menu-link-item`
198
+ - the semantic placement target: `page.section-nav`
199
+ - the placement owner: `admin-settings`
205
200
 
206
- That is why the simple settings-page commands do not need `--link-placement` or `--link-component-token`.
201
+ The renderer comes from `src/placementTopology.js`, where `page.section-nav` maps to the concrete `admin-settings:primary-menu` outlet for each layout class.
207
202
 
208
- The admin cog example is different. `w/[workspaceSlug]/admin/catalogue/index.vue` is just a normal admin page, so there is no local nested outlet to infer. That is why you must pass `--link-placement admin-cog:primary-menu` there.
203
+ That is why the simple settings-page commands do not need `--link-placement`.
204
+
205
+ The admin cog example is different. `w/[workspaceSlug]/admin/catalogue/index.vue` is just a normal admin page, so there is no local nested host to infer. That is why you must pass `--link-placement admin.tools-menu` there.
209
206
 
210
207
  If you want a little more context than the raw destination list, this is also useful:
211
208
 
@@ -42,7 +42,7 @@ This is the first chapter where the migration step is not just "nice to have."
42
42
  - `AUTH_PROFILE_MODE=users` into `.env`
43
43
  - real users/account schema migrations into `migrations/`
44
44
 
45
- That means the app is now expected to use the persistent users-backed profile sync service. If you skip `npm run db:migrate`, the code and routes are installed, but the required tables are still missing.
45
+ That means the app is expected to use the persistent users-backed profile sync service. If you skip `npm run db:migrate`, the code and routes are installed, but the required tables are still missing.
46
46
 
47
47
  So the correct flow is:
48
48
 
@@ -57,24 +57,24 @@ Most of the time, step 3 is not needed because `jskit add package users-web` alr
57
57
  - `jskit migrations changed` writes or refreshes JSKIT-managed migration files in `migrations/`
58
58
  - `npm run db:migrate` actually applies pending migrations to MySQL
59
59
 
60
- ## What changes now
60
+ ## What `users-web` adds
61
61
 
62
62
  This chapter is the real transition from "authentication exists" to "the app knows about users."
63
63
 
64
64
  ### Authentication becomes users-backed
65
65
 
66
- In the database chapter, JSKIT still used the standalone in-memory profile mirror. After installing `users-web`, that changes. JSKIT now expects to synchronize authenticated users into real JSKIT tables.
66
+ In the database chapter, JSKIT used the standalone in-memory profile mirror. After installing `users-web`, JSKIT expects to synchronize authenticated users into real JSKIT tables.
67
67
 
68
68
  That is the biggest architectural change in this chapter.
69
69
 
70
70
  - Supabase still owns the real auth identity and session
71
- - JSKIT now also owns a persistent users/account data model in MySQL
71
+ - JSKIT owns a persistent users/account data model in MySQL
72
72
 
73
- So after this chapter, a signed-in user is no longer only "someone Supabase knows about." They are also a persistent JSKIT-side user with settings and profile state in the app database.
73
+ So after this chapter, a signed-in user is not only "someone Supabase knows about." They are also a persistent JSKIT-side user with settings and profile state in the app database.
74
74
 
75
75
  ### The app gets an authenticated account surface
76
76
 
77
- The app now has a new authenticated surface at `/account`.
77
+ The app has an authenticated surface at `/account`.
78
78
 
79
79
  This is where the starter account settings UI lives. It already has real sections for:
80
80
 
@@ -84,17 +84,17 @@ This is where the starter account settings UI lives. It already has real section
84
84
 
85
85
  Later chapters can extend this account screen with more sections. For example, the multi-homing chapter adds workspace invitation UI through `workspaces-web`, not through `users-web` itself.
86
86
 
87
- The important point is that this is no longer just a placeholder route. It is the first app-owned screen that assumes there is a real persistent user model behind it.
87
+ The important point is that this is a real account route, not a placeholder. It is the first app-owned screen that assumes there is a persistent user model behind it.
88
88
 
89
89
  ### The shell changes for signed-in users
90
90
 
91
91
  Once a user is signed in, the shell becomes noticeably richer.
92
92
 
93
93
  - the profile menu gets a `Settings` entry that leads to `/account`
94
- - the home surface gets a small users tools widget in the top-right area
95
- - the auth bootstrap payload now includes persistent user settings instead of only the fallback mirror data
94
+ - the home surface gets a small users tools widget in `shell.status`
95
+ - the auth bootstrap payload includes persistent user settings instead of only the fallback mirror data
96
96
 
97
- So this chapter is also the first one where logging in changes more than just "guest vs signed in." It now changes what persistent user-facing surfaces the app can expose.
97
+ So this chapter is also the first one where logging in changes more than just "guest vs signed in." It changes what persistent user-facing surfaces the app can expose.
98
98
 
99
99
  ## What to look at in the browser
100
100
 
@@ -107,17 +107,17 @@ npm run server
107
107
 
108
108
  Then sign in through `http://localhost:5173/auth/login`.
109
109
 
110
- After a successful sign-in, you should notice three concrete differences compared with the previous chapter:
110
+ After a successful sign-in, check these concrete differences compared with the previous chapter:
111
111
 
112
- - the profile menu now contains `Settings`
113
- - the top-right area now also has a small users tools widget
114
- - `/account` now exists and is authenticated
112
+ - the profile menu contains `Settings`
113
+ - `shell.status` includes the users tools widget
114
+ - `/account` exists and is authenticated
115
115
 
116
116
  This is the first chapter where the app starts to feel like it has a real user model behind it.
117
117
 
118
118
  ## What `users-web` adds to the app
119
119
 
120
- The most interesting files now are spread across config, migrations, routing, and the app-owned account UI.
120
+ The most interesting files are spread across config, migrations, routing, and the app-owned account UI.
121
121
 
122
122
  ### `.env` flips auth into users mode
123
123
 
@@ -180,10 +180,10 @@ The placement registry also becomes more interesting:
180
180
  ```js
181
181
  addPlacement({
182
182
  id: "users.profile.menu.settings",
183
- target: "auth-profile-menu:primary-menu",
183
+ target: "auth.profile-menu",
184
+ kind: "link",
184
185
  surfaces: ["*"],
185
186
  order: 500,
186
- componentToken: "auth.web.profile.menu.link-item",
187
187
  props: {
188
188
  label: "Settings",
189
189
  to: "/account"
@@ -239,18 +239,18 @@ src/components/account/settings/
239
239
 
240
240
  Those three section components stay app-owned so you can reshape the actual UI freely.
241
241
 
242
- The host itself now lives in `users-web` and resolves every account section through the `account-settings:sections` placement target, including the default `profile`, `preferences`, and `notifications` entries.
242
+ The host itself lives in `users-web` and resolves every account section through the semantic `settings.sections` placement with owner `account-settings`, including the default `profile`, `preferences`, and `notifications` entries.
243
243
 
244
244
  So the screen follows the same rule as the rest of JSKIT UI: sections are added by placement rather than being hardcoded into an app-owned host component.
245
245
 
246
- That is worth noticing because the guide has now reached a new level of scaffolding:
246
+ That is worth noticing because this is a higher level of scaffolding:
247
247
 
248
248
  - earlier chapters mostly introduced shells and routes
249
249
  - this chapter introduces app-owned leaf section UI while the generic section host stays in the package
250
250
 
251
251
  ## Under the hood
252
252
 
253
- ### Why auth now behaves differently
253
+ ### Why auth uses the users layer
254
254
 
255
255
  In the previous chapter, auth still defaulted to the standalone profile sync fallback. The core logic in `AuthSupabaseServiceProvider` looks like this:
256
256
 
@@ -268,7 +268,7 @@ if (authProfileMode === AUTH_PROFILE_MODE_USERS) {
268
268
  }
269
269
  ```
270
270
 
271
- The important part is no longer hypothetical.
271
+ The important part is concrete.
272
272
 
273
273
  After `users-web`:
274
274
 
@@ -276,9 +276,9 @@ After `users-web`:
276
276
  - `users-core` supplies the users-backed sync service
277
277
  - the migrations supply the required tables
278
278
 
279
- So auth now has everything it needs to stop using the fallback mirror and start using the persistent users-backed one.
279
+ So auth has everything it needs to stop using the fallback mirror and start using the persistent users-backed one.
280
280
 
281
- That is the true point of this chapter. The app is no longer just authenticated. It now has a real users layer.
281
+ That is the true point of this chapter. The app is not just authenticated. It has a real users layer.
282
282
 
283
283
  ### `users-core` also owns the profile-sync lifecycle registry
284
284
 
@@ -361,7 +361,7 @@ This chapter is where the app stopped treating signed-in people as only Supabase
361
361
 
362
362
  That is why this chapter feels bigger than a normal page install. It changes both the browser experience and the server-side meaning of "a signed-in user."
363
363
 
364
- At the end of this chapter, the app now has:
364
+ At the end of this chapter, the app has:
365
365
 
366
366
  - real JSKIT-side `users` and `user_settings` tables
367
367
  - a real authenticated `/account` surface
@@ -71,14 +71,15 @@ In the current scaffold, those scripts are intentionally thin:
71
71
 
72
72
  That is a deliberate design choice.
73
73
 
74
- The app keeps the handy `npm run` names, but the real maintenance policy now lives in the installed CLI package instead of copied shell scripts inside the app. That means if JSKIT later changes how package updates, local linking, or baseline verification should work, apps can pick up the new behavior by updating `@jskit-ai/jskit-cli` instead of hand-editing frozen scaffold files.
74
+ The app keeps the handy `npm run` names, but the real maintenance policy lives in the installed CLI package instead of copied shell scripts inside the app. That means if JSKIT later changes how package updates, local linking, or baseline verification should work, apps can pick up the new behavior by updating `@jskit-ai/jskit-cli` instead of hand-editing frozen scaffold files.
75
75
 
76
76
  This gives you a clean ownership split:
77
77
 
78
78
  - app-owned scripts still describe how *this app* runs, builds, and tests
79
+ - `npm run devlinks` re-applies local checkout links after `npm install` when you are testing an app against this monorepo
79
80
  - JSKIT-owned wrapper scripts delegate framework maintenance to `jskit app ...`
80
81
 
81
- That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, that is now shorthand for "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
82
+ That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, read it as "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
82
83
 
83
84
  The starter scaffold also includes `.github/workflows/verify.yml`. That workflow is intentionally conservative: it runs `npm run verify` and does not assume that every app can stand up full browser, auth, seed-data, and database verification inside hosted CI.
84
85
 
@@ -332,8 +333,8 @@ The placement sections are often the most useful part of `show --details`.
332
333
 
333
334
  For `@jskit-ai/workspaces-web`, the detailed output shows placement contributions such as:
334
335
 
335
- - the workspace selector in `shell-layout:top-left`
336
- - the pending invites cue in `shell-layout:top-right`
336
+ - the workspace selector in `shell.identity`
337
+ - the pending invites cue in `shell.status`
337
338
  - the workspace tools widget on the `admin` surface
338
339
  - the `Members` and workspace settings menu entries
339
340
 
@@ -341,9 +342,10 @@ That lets you answer a very concrete question before installing anything:
341
342
 
342
343
  - *what will change in the shell if I add this package?*
343
344
 
344
- It also shows placement outlets, such as:
345
+ It also shows semantic placement topology, such as:
345
346
 
346
- - `admin-settings:primary-menu`
347
+ - `page.section-nav` with owner `admin-settings`
348
+ - `admin.tools-menu`
347
349
 
348
350
  which helps you understand where later app-owned pages or settings links can attach.
349
351
 
@@ -504,7 +506,13 @@ npx jskit add package shell-web
504
506
  npm install
505
507
  ```
506
508
 
507
- `jskit add` changes the app. `npm install` downloads the dependencies that the changed app now requires.
509
+ `jskit add` changes the app. `npm install` downloads the dependencies that the changed app requires.
510
+
511
+ If the app is being tested against a local JSKIT checkout with linked packages, run the local-link wrapper again after every `npm install`:
512
+
513
+ ```bash
514
+ npm run devlinks
515
+ ```
508
516
 
509
517
  ### `add bundle`
510
518
 
@@ -699,7 +707,7 @@ That is a different job from:
699
707
 
700
708
  Those commands can all pass while JSKIT-managed state is still inconsistent. `doctor` is the command that checks that JSKIT's own view of the app still makes sense.
701
709
 
702
- That is exactly why the starter scaffold now routes `npm run verify` through `jskit app verify`.
710
+ That is exactly why the starter scaffold routes `npm run verify` through `jskit app verify`.
703
711
 
704
712
  It belongs there because JSKIT apps are not only source trees. They also have:
705
713
 
@@ -731,7 +739,7 @@ Good times to run it manually include:
731
739
 
732
740
  One important nuance: `doctor` is checking for broken JSKIT ownership and visibility, not trying to stop you from editing app-owned files. For example, a managed file that still exists but whose contents changed is normally fine. The problem is when JSKIT expects a managed file to exist and it is gone, or when the installed package state no longer resolves cleanly.
733
741
 
734
- There is one intentional exception now for user-facing UI work.
742
+ There is one intentional exception for user-facing UI work.
735
743
 
736
744
  If the current git working tree has changed UI files under the app's normal UI paths, `doctor` expects a matching `.jskit/verification/ui.json` receipt. The intended way to create that receipt is:
737
745
 
@@ -961,7 +969,7 @@ Good fits include:
961
969
  - a custom integration package that talks to one external API
962
970
  - app-specific auth or policy behavior
963
971
  - a local runtime package that owns both client and server behavior for one feature area
964
- - a package that starts small now but may later grow providers, shared helpers, and routes
972
+ - a package that starts small but may later grow providers, shared helpers, and routes
965
973
 
966
974
  Use a generator when the problem is already understood well enough that JSKIT can scaffold the feature shape for you.
967
975