@jskit-ai/agent-docs 0.1.26 → 0.1.27

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 (29) hide show
  1. package/guide/agent/app-extras/assistant.md +7 -18
  2. package/guide/agent/app-extras/mobile-capacitor.md +374 -0
  3. package/guide/agent/app-extras/realtime.md +2 -1
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +54 -47
  5. package/guide/agent/app-setup/authentication.md +10 -9
  6. package/guide/agent/app-setup/console.md +3 -3
  7. package/guide/agent/app-setup/multi-homing.md +22 -19
  8. package/guide/agent/app-setup/quickstart.md +11 -14
  9. package/guide/agent/app-setup/users.md +3 -3
  10. package/guide/agent/app-setup/working-with-the-jskit-cli.md +5 -4
  11. package/guide/agent/generators/ui-generators.md +29 -23
  12. package/guide/agent/index.md +3 -2
  13. package/package.json +1 -1
  14. package/patterns/page-scaffolding.md +3 -2
  15. package/patterns/placements.md +7 -1
  16. package/reference/autogen/KERNEL_MAP.md +16 -0
  17. package/reference/autogen/README.md +3 -0
  18. package/reference/autogen/packages/assistant.md +1 -0
  19. package/reference/autogen/packages/auth-web.md +20 -1
  20. package/reference/autogen/packages/crud-ui-generator.md +1 -0
  21. package/reference/autogen/packages/google-rewarded-core.md +222 -0
  22. package/reference/autogen/packages/google-rewarded-web.md +71 -0
  23. package/reference/autogen/packages/kernel.md +58 -6
  24. package/reference/autogen/packages/mobile-capacitor.md +76 -0
  25. package/reference/autogen/packages/shell-web.md +13 -0
  26. package/reference/autogen/packages/ui-generator.md +11 -0
  27. package/reference/autogen/packages/users-web.md +0 -1
  28. package/reference/autogen/packages/workspaces-web.md +0 -1
  29. package/reference/autogen/tooling/jskit-cli.md +98 -9
@@ -53,7 +53,7 @@ Open `http://localhost:5173/home/settings` in the browser to see that nested set
53
53
 
54
54
  The most important new idea in `shell-web` is that the app now has _specific, named places_ where UI can be inserted later. JSKIT calls those places _placements_. In practice, this means later packages or generators do not have to rewrite the whole shell every time they want to add a menu entry, a widget, or a settings section.
55
55
 
56
- Start by asking JSKIT what placement targets already exist:
56
+ Start by asking JSKIT what public placement targets already exist:
57
57
 
58
58
  ```bash
59
59
  npx jskit list-placements
@@ -63,16 +63,25 @@ In a fresh `shell-web` app, the result looks like this:
63
63
 
64
64
  ```text
65
65
  Available placements:
66
- - home-settings:primary-menu [src/pages/home/settings.vue]
67
- - shell-layout:primary-menu (default) [src/components/ShellLayout.vue]
68
- - shell-layout:secondary-menu [src/components/ShellLayout.vue]
69
- - shell-layout:top-left [src/components/ShellLayout.vue]
70
- - shell-layout:top-right [src/components/ShellLayout.vue]
66
+ - shell.primary-nav (default): Primary top-level navigation for the current surface.
67
+ - compact -> shell-layout:primary-menu
68
+ - medium -> shell-layout:primary-menu
69
+ - expanded -> shell-layout:primary-menu
70
+ - page.section-nav [owner:home-settings]: Navigation between child pages in the home settings section.
71
+ - compact -> home-settings:primary-menu
72
+ - medium -> home-settings:primary-menu
73
+ - expanded -> home-settings:primary-menu
71
74
  ```
72
75
 
73
- This command lists placement targets, not the content inside them. That is why the output is about target names and source files. Later, when you place things into the shell, this list stays the same unless you add or remove a `ShellOutlet` in source.
76
+ This command lists semantic placements, not the content inside them. Later, when you place things into the shell, this list stays stable unless the public placement topology changes.
74
77
 
75
- Those target names come from real `ShellOutlet` elements in the app. See `src/components/ShellLayout.vue`:
78
+ The concrete outlets still exist, but they are implementation details. If you need to inspect them directly, use:
79
+
80
+ ```bash
81
+ npx jskit list-placements --concrete
82
+ ```
83
+
84
+ Those concrete target names come from real `ShellOutlet` elements in the app. See `src/components/ShellLayout.vue`:
76
85
 
77
86
  ```html
78
87
  ...
@@ -83,27 +92,20 @@ Those target names come from real `ShellOutlet` elements in the app. See `src/co
83
92
  <ShellOutlet
84
93
  target="shell-layout:primary-menu"
85
94
  default
86
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
87
95
  />
88
96
  ...
89
- <ShellOutlet
90
- target="shell-layout:secondary-menu"
91
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
92
- />
97
+ <ShellOutlet target="shell-layout:secondary-menu" />
93
98
  ```
94
99
 
95
100
  And the settings page introduces its own nested outlet in `src/pages/home/settings.vue`:
96
101
 
97
102
  ```html
98
- <ShellOutlet
99
- target="home-settings:primary-menu"
100
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
101
- />
103
+ <ShellOutlet target="home-settings:primary-menu" />
102
104
  ```
103
105
 
104
106
  That nested example matters. It shows that the shell is not the only place that can host placements. A page inside the shell can define its own insertion point too. That is how JSKIT can later build menus inside sections such as settings without rewriting the whole shell.
105
107
 
106
- Just as importantly, `shell-web` already uses that placement system itself. The starter app is not only exposing placement targets; it is also seeding real placement entries into them. The drawer gets `Home` and `Settings`, and the nested settings menu gets `General`. That is why the shell already feels real before you generate anything of your own.
108
+ Just as importantly, `shell-web` already uses that placement system itself. The starter app is not only exposing semantic placement targets; it is also seeding real placement entries into them. The drawer gets `Home` and `Settings`, and the nested settings menu gets `General`. That is why the shell already feels real before you generate anything of your own.
107
109
 
108
110
  The shell also ships with a few app-owned component tokens that it can use as default link renderers. You can inspect those too:
109
111
 
@@ -133,7 +135,7 @@ To add a small UI element to the shell itself:
133
135
  npx jskit generate ui-generator placed-element --name "Alerts Widget"
134
136
  ```
135
137
 
136
- That command creates a Vue component under `src/components/` (in this case `src/components/AlertsWidgetElement.vue`), registers a new local token for it, and adds a placement entry targeting `shell-layout:top-right`. After running it, refresh the home page in the browser. The shell now has a real app-owned widget living inside one of its named placement targets.
138
+ That command creates a Vue component under `src/components/` (in this case `src/components/AlertsWidgetElement.vue`), registers a new local token for it, and adds a placement entry targeting `shell.status`. After running it, refresh the home page in the browser. The shell now has a real app-owned widget living inside one of its named placement targets.
137
139
 
138
140
  In this app, there is no need to pass `--surface`: since the app only has one enabled surface, JSKIT can infer it automatically.
139
141
 
@@ -141,13 +143,13 @@ In this app, there is no need to pass `--surface`: since the app only has one en
141
143
 
142
144
  The settings host uses the same placement machinery, but the normal way to grow it is not by dropping a free-standing widget there. The more interesting case is adding a child page and letting JSKIT wire the menu entry for you.
143
145
 
144
- The source path in the `list-placements` output helps you reason about where child pages belong. When you see:
146
+ The owner in the `list-placements` output helps you reason about where child pages belong. When you see:
145
147
 
146
148
  ```text
147
- - home-settings:primary-menu [src/pages/home/settings.vue]
149
+ - page.section-nav [owner:home-settings]
148
150
  ```
149
151
 
150
- you know that the outlet lives in the settings host page. So if you want a child page to appear in that menu, you should create it under that part of the route tree instead of treating the menu like a generic widget area. For example, `src/pages/home/settings/profile/index.vue` belongs to that settings section, so JSKIT can wire its preferred menu entry into `home-settings:primary-menu` automatically.
152
+ you know that the semantic placement is owned by the settings host page. So if you want a child page to appear in that menu, you should create it under that part of the route tree instead of treating the menu like a generic widget area. For example, `src/pages/home/settings/profile/index.vue` belongs to that settings section, so JSKIT can wire its preferred menu entry into `page.section-nav` with owner `home-settings` automatically.
151
153
 
152
154
  Now use the settings host the way it is normally meant to be used: add a real child page under it.
153
155
 
@@ -155,7 +157,7 @@ Now use the settings host the way it is normally meant to be used: add a real ch
155
157
  npx jskit generate ui-generator page home/settings/profile/index.vue --name "Profile"
156
158
  ```
157
159
 
158
- This is a more interesting example than the widget case. JSKIT creates the page file, notices that `src/pages/home/settings.vue` owns the `home-settings:primary-menu` outlet, and adds the preferred menu entry there automatically. You do not have to write that placement entry by hand.
160
+ This is a more interesting example than the widget case. JSKIT creates the page file, notices that `src/pages/home/settings.vue` owns the settings section navigation, and adds the preferred semantic menu entry there automatically. You do not have to write that placement entry by hand.
159
161
 
160
162
  Open `/home/settings/profile` in the browser. The settings shell now shows a second real child page and a second real menu entry created by the same page-generation command. `General` was already there from `shell-web`; `Profile` is the first additional settings page you add yourself. This is the important part of the chapter: the exact same placement system works both at the top shell level and inside a page-owned nested outlet.
161
163
 
@@ -165,7 +167,7 @@ Now add a second sibling page:
165
167
  npx jskit generate ui-generator page home/settings/notifications/index.vue --name "Notifications"
166
168
  ```
167
169
 
168
- Open `/home/settings/notifications` in the browser. You now get a third settings menu entry without touching `settings.vue`, without writing a second menu component, and without hand-editing `src/placement.js`. JSKIT appends another placement entry targeting the same `home-settings:primary-menu` outlet, so the links simply stack in the menu for free.
170
+ Open `/home/settings/notifications` in the browser. You now get a third settings menu entry without touching `settings.vue`, without writing a second menu component, and without hand-editing `src/placement.js`. JSKIT appends another placement entry targeting the same `page.section-nav` owner, so the links simply stack in the menu for free.
169
171
 
170
172
  The order is also easy to reason about:
171
173
 
@@ -191,7 +193,7 @@ definePage({
191
193
  });
192
194
  ```
193
195
 
194
- This is why the `home-settings:primary-menu` outlet from `list-placements` is such a useful clue: it tells you which page is acting as the host.
196
+ This is why the `page.section-nav` owner from `list-placements` is such a useful clue: it tells you which page is acting as the host.
195
197
 
196
198
  Even an `index.vue` page can have children. If you want an index page to stay visible while child routes render underneath it, put those children under an `index/` directory such as `src/pages/home/settings/profile/index/details.vue`.
197
199
 
@@ -209,8 +211,10 @@ In placement metadata, raw `mdi-*` strings are acceptable because the shell menu
209
211
  ```js
210
212
  addPlacement({
211
213
  id: "home.settings.profile.link",
212
- target: "home-settings:primary-menu",
213
- componentToken: "local.main.ui.surface-aware-menu-link-item",
214
+ target: "page.section-nav",
215
+ owner: "home-settings",
216
+ kind: "link",
217
+ surfaces: ["home"],
214
218
  props: {
215
219
  label: "Profile",
216
220
  to: "./profile",
@@ -382,10 +386,10 @@ After the `shell-web` install plus the `placed-element` and `page` commands from
382
386
  ```js
383
387
  addPlacement({
384
388
  id: "shell-web.home.menu.home",
385
- target: "shell-layout:primary-menu",
386
- surfaces: ["*"],
389
+ target: "shell.primary-nav",
390
+ kind: "link",
391
+ surfaces: ["home"],
387
392
  order: 50,
388
- componentToken: "local.main.ui.surface-aware-menu-link-item",
389
393
  props: {
390
394
  label: "Home",
391
395
  surface: "home",
@@ -397,10 +401,10 @@ addPlacement({
397
401
 
398
402
  addPlacement({
399
403
  id: "shell-web.home.menu.settings",
400
- target: "shell-layout:primary-menu",
404
+ target: "shell.primary-nav",
405
+ kind: "link",
401
406
  surfaces: ["home"],
402
407
  order: 100,
403
- componentToken: "local.main.ui.surface-aware-menu-link-item",
404
408
  props: {
405
409
  label: "Settings",
406
410
  surface: "home",
@@ -411,10 +415,11 @@ addPlacement({
411
415
 
412
416
  addPlacement({
413
417
  id: "shell-web.home.settings.general",
414
- target: "home-settings:primary-menu",
418
+ target: "page.section-nav",
419
+ owner: "home-settings",
420
+ kind: "link",
415
421
  surfaces: ["home"],
416
422
  order: 100,
417
- componentToken: "local.main.ui.surface-aware-menu-link-item",
418
423
  props: {
419
424
  label: "General",
420
425
  surface: "home",
@@ -426,7 +431,8 @@ addPlacement({
426
431
 
427
432
  addPlacement({
428
433
  id: "ui-generator.element.alerts-widget",
429
- target: "shell-layout:top-right",
434
+ target: "shell.status",
435
+ kind: "component",
430
436
  surfaces: ["home"],
431
437
  order: 155,
432
438
  componentToken: "local.main.ui.element.alerts-widget"
@@ -434,10 +440,11 @@ addPlacement({
434
440
 
435
441
  addPlacement({
436
442
  id: "ui-generator.page.home.settings.profile.link",
437
- target: "home-settings:primary-menu",
443
+ target: "page.section-nav",
444
+ owner: "home-settings",
445
+ kind: "link",
438
446
  surfaces: ["home"],
439
447
  order: 155,
440
- componentToken: "local.main.ui.surface-aware-menu-link-item",
441
448
  props: {
442
449
  label: "Profile",
443
450
  surface: "home",
@@ -449,10 +456,11 @@ addPlacement({
449
456
 
450
457
  addPlacement({
451
458
  id: "ui-generator.page.home.settings.notifications.link",
452
- target: "home-settings:primary-menu",
459
+ target: "page.section-nav",
460
+ owner: "home-settings",
461
+ kind: "link",
453
462
  surfaces: ["home"],
454
463
  order: 155,
455
- componentToken: "local.main.ui.surface-aware-menu-link-item",
456
464
  props: {
457
465
  label: "Notifications",
458
466
  surface: "home",
@@ -465,13 +473,15 @@ addPlacement({
465
473
 
466
474
  That snippet shows the full placement contract clearly:
467
475
 
468
- - the target says where the UI should go
469
- - the component token says what should render that entry
476
+ - the target says which semantic placement should receive the entry
477
+ - the owner disambiguates page-owned semantic placements such as `page.section-nav`
478
+ - `kind: "link"` lets topology choose the concrete link renderer for the current layout
479
+ - component placements still provide their own `componentToken`
470
480
  - `props.to` tells the generated menu link which child route to open
471
481
  - `props.icon`, when you add one, belongs to menu metadata rather than direct Vuetify icon rendering
472
482
  - the surface list says where it is active
473
483
  - lower `order` values come first
474
- - when multiple entries target the same outlet with the same order, the shell keeps their source order
484
+ - when multiple entries target the same semantic placement with the same order, the shell keeps their source order
475
485
 
476
486
  That is why the settings menu now shows `General` first, followed by `Profile` and `Notifications`: `General` is seeded by `shell-web` with a lower order, while the two generated pages share the same later order and keep their source order.
477
487
 
@@ -616,10 +626,7 @@ The important host file is still `src/pages/home/settings.vue`:
616
626
 
617
627
  ```vue
618
628
  <v-list nav density="comfortable" rounded="lg" border>
619
- <ShellOutlet
620
- target="home-settings:primary-menu"
621
- default-link-component-token="local.main.ui.surface-aware-menu-link-item"
622
- />
629
+ <ShellOutlet target="home-settings:primary-menu" />
623
630
  </v-list>
624
631
 
625
632
  <RouterView />
@@ -631,7 +638,7 @@ The starter shell now uses a real child-page structure right away:
631
638
 
632
639
  - `src/pages/home/settings/index.vue` is only a redirect into the first child page
633
640
  - `src/pages/home/settings/general/index.vue` is the first real settings page
634
- - `src/placement.js` already seeds a `General` link into `home-settings:primary-menu`
641
+ - `src/placement.js` already seeds a `General` link into `page.section-nav` with owner `home-settings`
635
642
 
636
643
  When you need that landing redirect yourself, use the same helper pattern:
637
644
 
@@ -319,10 +319,10 @@ The placement entry is just a normal shell link:
319
319
  ```js
320
320
  addPlacement({
321
321
  id: "ui-generator.page.home.reports.link",
322
- target: "shell-layout:primary-menu",
322
+ target: "shell.primary-nav",
323
+ kind: "link",
323
324
  surfaces: ["home"],
324
325
  order: 155,
325
- componentToken: "local.main.ui.surface-aware-menu-link-item",
326
326
  props: {
327
327
  label: "Reports",
328
328
  surface: "home",
@@ -390,10 +390,10 @@ To hide the `Reports` menu entry until the user is logged in, update the placeme
390
390
  ```js
391
391
  addPlacement({
392
392
  id: "ui-generator.page.home.reports.link",
393
- target: "shell-layout:primary-menu",
393
+ target: "shell.primary-nav",
394
+ kind: "link",
394
395
  surfaces: ["home"],
395
396
  order: 155,
396
- componentToken: "local.main.ui.surface-aware-menu-link-item",
397
397
  props: {
398
398
  label: "Reports",
399
399
  surface: "home",
@@ -606,7 +606,8 @@ Authentication also becomes visible in the shell through `src/placement.js`:
606
606
  ```js
607
607
  addPlacement({
608
608
  id: "auth.profile.widget",
609
- target: "shell-layout:top-right",
609
+ target: "shell.status",
610
+ kind: "component",
610
611
  surfaces: ["*"],
611
612
  order: 1000,
612
613
  componentToken: "auth.web.profile.widget"
@@ -614,10 +615,10 @@ addPlacement({
614
615
 
615
616
  addPlacement({
616
617
  id: "auth.profile.menu.sign-in",
617
- target: "auth-profile-menu:primary-menu",
618
+ target: "auth.profile-menu",
619
+ kind: "link",
618
620
  surfaces: ["*"],
619
621
  order: 200,
620
- componentToken: "auth.web.profile.menu.link-item",
621
622
  props: {
622
623
  label: "Sign in",
623
624
  to: "/auth/login"
@@ -627,10 +628,10 @@ addPlacement({
627
628
 
628
629
  addPlacement({
629
630
  id: "auth.profile.menu.sign-out",
630
- target: "auth-profile-menu:primary-menu",
631
+ target: "auth.profile-menu",
632
+ kind: "link",
631
633
  surfaces: ["*"],
632
634
  order: 1000,
633
- componentToken: "auth.web.profile.menu.link-item",
634
635
  props: {
635
636
  label: "Sign out",
636
637
  to: "/auth/signout"
@@ -179,7 +179,7 @@ This follows the same route-owner pattern the guide has already shown on `home`
179
179
  - `src/pages/console/settings.vue` is the nested settings shell
180
180
  - `src/pages/console/settings/index.vue` is the initial developer-owned stub
181
181
 
182
- That last file is intentionally empty, because later modules are expected to add real console settings sections into the `console-settings:primary-menu` outlet.
182
+ That last file is intentionally empty, because later modules are expected to add real console settings sections through `page.section-nav` with owner `console-settings`.
183
183
 
184
184
  ### `src/placement.js` wires the first console menu entry
185
185
 
@@ -188,10 +188,10 @@ The starter placement block is:
188
188
  ```js
189
189
  addPlacement({
190
190
  id: "console.web.menu.settings",
191
- target: "shell-layout:primary-menu",
191
+ target: "shell.primary-nav",
192
+ kind: "link",
192
193
  surfaces: ["console"],
193
194
  order: 100,
194
- componentToken: "local.main.ui.menu-link-item",
195
195
  props: {
196
196
  label: "Settings",
197
197
  to: "/console/settings",
@@ -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,7 +575,8 @@ 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"
@@ -588,7 +591,7 @@ That one block explains a lot of the new shell behavior.
588
591
  - the admin surface gets workspace tools in the top-right area
589
592
  - the admin workspace settings menu is now 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
@@ -597,25 +600,25 @@ npx jskit list-placements
597
600
  In a workspace-enabled app, that list now 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
623
  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.
621
624
 
@@ -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
 
@@ -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,7 +239,7 @@ 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 now 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
 
@@ -332,8 +332,8 @@ The placement sections are often the most useful part of `show --details`.
332
332
 
333
333
  For `@jskit-ai/workspaces-web`, the detailed output shows placement contributions such as:
334
334
 
335
- - the workspace selector in `shell-layout:top-left`
336
- - the pending invites cue in `shell-layout:top-right`
335
+ - the workspace selector in `shell.identity`
336
+ - the pending invites cue in `shell.status`
337
337
  - the workspace tools widget on the `admin` surface
338
338
  - the `Members` and workspace settings menu entries
339
339
 
@@ -341,9 +341,10 @@ That lets you answer a very concrete question before installing anything:
341
341
 
342
342
  - *what will change in the shell if I add this package?*
343
343
 
344
- It also shows placement outlets, such as:
344
+ It also shows semantic placement topology, such as:
345
345
 
346
- - `admin-settings:primary-menu`
346
+ - `page.section-nav` with owner `admin-settings`
347
+ - `admin.tools-menu`
347
348
 
348
349
  which helps you understand where later app-owned pages or settings links can attach.
349
350