@elevasis/sdk 1.20.1 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cli.cjs +3388 -1530
  2. package/dist/index.d.ts +412 -149
  3. package/dist/index.js +955 -721
  4. package/dist/node/index.d.ts +0 -3
  5. package/dist/node/index.js +22 -49
  6. package/dist/test-utils/index.d.ts +395 -128
  7. package/dist/test-utils/index.js +599 -368
  8. package/dist/worker/index.js +536 -323
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +9 -7
  11. package/reference/_reference-manifest.json +1 -1
  12. package/reference/claude-config/rules/agent-start-here.md +4 -0
  13. package/reference/claude-config/rules/frontend.md +2 -2
  14. package/reference/claude-config/rules/organization-model.md +44 -2
  15. package/reference/claude-config/rules/organization-os.md +12 -12
  16. package/reference/claude-config/rules/ui.md +14 -14
  17. package/reference/claude-config/rules/vibe.md +37 -33
  18. package/reference/claude-config/skills/explore/SKILL.md +6 -6
  19. package/reference/claude-config/skills/knowledge/SKILL.md +73 -29
  20. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +1 -1
  21. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +25 -24
  22. package/reference/claude-config/skills/knowledge/operations/features.md +56 -93
  23. package/reference/claude-config/skills/knowledge/operations/labels.md +19 -14
  24. package/reference/claude-config/skills/knowledge/operations/offerings.md +6 -6
  25. package/reference/claude-config/skills/save/SKILL.md +2 -2
  26. package/reference/claude-config/skills/setup/SKILL.md +1 -1
  27. package/reference/claude-config/skills/tutorial/technical.md +23 -26
  28. package/reference/claude-config/skills/tutorial/vibe-coder.md +9 -9
  29. package/reference/claude-config/sync-notes/2026-05-12-sdk-ready-release-train.md +30 -0
  30. package/reference/cli.mdx +140 -0
  31. package/reference/deployment/provided-features.mdx +29 -15
  32. package/reference/examples/organization-model.ts +1 -1
  33. package/reference/packages/core/src/knowledge/README.md +8 -7
  34. package/reference/packages/core/src/organization-model/README.md +66 -26
  35. package/reference/packages/ui/src/provider/README.md +5 -5
  36. package/reference/scaffold/core/organization-graph.mdx +16 -15
  37. package/reference/scaffold/core/organization-model.mdx +89 -41
  38. package/reference/scaffold/index.mdx +9 -9
  39. package/reference/scaffold/operations/propagation-pipeline.md +3 -3
  40. package/reference/scaffold/operations/scaffold-maintenance.md +11 -11
  41. package/reference/scaffold/recipes/add-a-feature.md +26 -24
  42. package/reference/scaffold/recipes/add-a-resource.md +10 -14
  43. package/reference/scaffold/recipes/customize-crm-actions.md +439 -439
  44. package/reference/scaffold/recipes/customize-knowledge-browser.md +384 -0
  45. package/reference/scaffold/recipes/customize-organization-model.md +72 -44
  46. package/reference/scaffold/recipes/extend-crm.md +40 -39
  47. package/reference/scaffold/recipes/extend-lead-gen.md +15 -16
  48. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +34 -30
  49. package/reference/scaffold/recipes/index.md +13 -12
  50. package/reference/scaffold/recipes/query-the-knowledge-graph.md +200 -0
  51. package/reference/scaffold/reference/contracts.md +362 -99
  52. package/reference/scaffold/reference/feature-registry.md +9 -20
  53. package/reference/scaffold/reference/glossary.md +18 -18
  54. package/reference/scaffold/ui/composition-extensibility.mdx +23 -23
  55. package/reference/scaffold/ui/customization.md +11 -11
  56. package/reference/scaffold/ui/feature-flags-and-gating.md +8 -8
  57. package/reference/scaffold/ui/feature-shell.mdx +19 -19
  58. package/reference/scaffold/ui/recipes.md +29 -28
@@ -0,0 +1,384 @@
1
+ <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
2
+ <!-- Regenerate: pnpm scaffold:sync -->
3
+
4
+ ---
5
+ title: Customize Knowledge Browser
6
+ description: Author knowledge nodes and customize the Knowledge Browser in a template-derived project -- from zero-config authoring through sidebar composition, custom dispatchers, and direct query access.
7
+ ---
8
+
9
+ # Customize Knowledge Browser
10
+
11
+ The Knowledge Browser is a built-in feature surface that renders MDX documents called knowledge nodes. In template-derived projects it is pre-wired and ready to use without any configuration changes.
12
+
13
+ ## How It Works
14
+
15
+ In template-derived projects, `ui/vite.config.ts` imports `elevasisVite` from `@elevasis/ui/vite` and spreads it into the plugins array:
16
+
17
+ ```ts
18
+ // ui/vite.config.ts
19
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
20
+ import { elevasisVite } from '@elevasis/ui/vite'
21
+
22
+ export default defineConfig({
23
+ plugins: [tanstackRouter({ autoCodeSplitting: true }), react(), ...elevasisVite()],
24
+ })
25
+ ```
26
+
27
+ `elevasisVite()` includes `knowledgePlugin()` as one of the plugins it returns. The plugin runs MDX codegen at `buildStart` and handles hot-module updates during `vite dev`. You do not need to touch `vite.config.ts` for the Knowledge Browser to work.
28
+
29
+ Knowledge node icons are authored as semantic data tokens in MDX frontmatter, not as UI library component names. Use `knowledge.playbook`, `knowledge.strategy`, or `knowledge.reference` by node kind, or a project-owned `custom.*` token when the platform catalog does not cover the concept.
30
+
31
+ ## Author a Knowledge Node
32
+
33
+ Drop an `.mdx` file anywhere under `core/config/knowledge/nodes/`. Subdirectories are fine -- codegen walks the tree recursively.
34
+
35
+ Required frontmatter fields:
36
+
37
+ - `id` -- unique string; convention is `knowledge.{slug}`
38
+ - `kind` -- one of `playbook`, `strategy`, or `reference`
39
+ - `title` -- display title shown in the Browser tree
40
+ - `description` -- one-sentence summary shown in search results
41
+ - `updatedAt` -- ISO date string (e.g. `2026-05-04`)
42
+
43
+ Optional frontmatter fields:
44
+
45
+ - `icon` -- semantic token such as `knowledge.playbook` (defaults by kind if omitted)
46
+ - `links` -- array of node IDs or System references this node relates to
47
+ - `ownerIds` -- array of role IDs that own or maintain this node
48
+
49
+ Example:
50
+
51
+ ```mdx
52
+ ---
53
+ id: knowledge.internal-runbook
54
+ kind: playbook
55
+ title: Internal Runbook
56
+ description: Operating notes for project-specific support and escalation.
57
+ icon: knowledge.playbook
58
+ ownerIds:
59
+ - role.operator
60
+ links:
61
+ - system:operations
62
+ updatedAt: 2026-05-04
63
+ ---
64
+
65
+ ## Body content here
66
+
67
+ Write plain markdown. A small JSX component allowlist is available in the body:
68
+ `Card`, `Cards`, `Step`, `Steps`, `Callout`, `Tab`, `Tabs`.
69
+ ```
70
+
71
+ On the next dev hot-reload or production build the node appears in the Browser. No manual command is required.
72
+
73
+ The template ships a starter node at `core/config/knowledge/nodes/welcome.mdx` so the first `pnpm -C ui dev` produces a non-empty Browser. Delete or rewrite it once you have authored your own nodes.
74
+
75
+ ## `elevasis-sdk knowledge:generate` -- Manual One-Shot
76
+
77
+ The CLI command `elevasis-sdk knowledge:generate` refreshes `core/config/knowledge/_generated/nodes.ts` outside a dev or build cycle. It is useful for two situations:
78
+
79
+ - Force-refreshing generated output without starting `vite dev` or running `vite build`
80
+ - Pre-build pipelines that must compile MDX before TypeScript starts
81
+
82
+ The template's `pnpm -C ui build` script calls `pnpm -C .. knowledge:generate` explicitly before `tsc` and `vite build`, so production builds regenerate nodes as a first step without requiring a running dev server.
83
+
84
+ During development the Vite plugin handles codegen automatically on every save. You do not need to run the CLI command manually unless you are operating outside a dev or build cycle.
85
+
86
+ ## CSS
87
+
88
+ Import the knowledge subpath CSS in your app entry point:
89
+
90
+ ```ts
91
+ // ui/src/main.tsx
92
+ import '@elevasis/ui/knowledge/index.css'
93
+ ```
94
+
95
+ This is required for Mantine-based knowledge components to render correctly. The CSS is not auto-loaded -- per the `@elevasis/ui` publish rules, consumers import CSS subpaths explicitly.
96
+
97
+ ## Customization
98
+
99
+ The sections below cover optional customization for projects that need to diverge from the platform default. The authoring steps above are sufficient for the common case.
100
+
101
+ ### Default Mount (What the Template Ships)
102
+
103
+ The template's `ui/src/routes/__root.tsx` registers `knowledgeManifest` from `@elevasis/ui/features/knowledge` in the `ElevasisSystemsProvider` manifest array. That is all that is required for the default Knowledge Browser to appear. The template already does this -- you do not need to add it yourself unless you scaffolded the project manually without using the template.
104
+
105
+ ```tsx
106
+ // ui/src/routes/__root.tsx
107
+ import { knowledgeManifest } from '@elevasis/ui/features/knowledge'
108
+ import { ElevasisSystemsProvider } from '@elevasis/ui'
109
+
110
+ <ElevasisSystemsProvider
111
+ organizationModel={canonicalOrganizationModel}
112
+ systems={[crmManifest, leadGenManifest, knowledgeManifest]}
113
+ >
114
+ {/* ... */}
115
+ </ElevasisSystemsProvider>
116
+ ```
117
+
118
+ A "Knowledge" sidebar entry appears, routes resolve under `/knowledge`, and the Browser renders with the default tree and node viewer. No additional code required.
119
+
120
+ ### Extend (Custom Nav Items, Default Chrome)
121
+
122
+ Spread the manifest and override `sidebar` to a custom component. The custom component composes `KnowledgeSidebarMiddle` with a modified items array. This is the shortest path to adding project-specific nav entries while keeping the platform chrome.
123
+
124
+ ```tsx
125
+ // ui/src/features/knowledge/sidebar.tsx
126
+ import {
127
+ KnowledgeSidebarMiddle,
128
+ KNOWLEDGE_ITEMS,
129
+ } from '@elevasis/ui/knowledge'
130
+ import { knowledgeManifest, KnowledgeSidebar } from '@elevasis/ui/features/knowledge'
131
+ import { IconBook } from '@tabler/icons-react'
132
+
133
+ const customItems = [
134
+ ...KNOWLEDGE_ITEMS,
135
+ {
136
+ label: 'Internal Runbooks',
137
+ to: '/knowledge/by-owner/internal',
138
+ icon: IconBook,
139
+ exact: false,
140
+ },
141
+ ]
142
+
143
+ const CustomKnowledgeSidebar = () => (
144
+ <KnowledgeSidebar>
145
+ <KnowledgeSidebarMiddle items={customItems} />
146
+ </KnowledgeSidebar>
147
+ )
148
+
149
+ export const customKnowledgeManifest = {
150
+ ...knowledgeManifest,
151
+ sidebar: CustomKnowledgeSidebar,
152
+ }
153
+ ```
154
+
155
+ Register the custom manifest in place of the default:
156
+
157
+ ```tsx
158
+ // ui/src/routes/__root.tsx
159
+ import { customKnowledgeManifest } from '../features/knowledge/sidebar'
160
+
161
+ <ElevasisSystemsProvider
162
+ systems={[crmManifest, leadGenManifest, customKnowledgeManifest]}
163
+ >
164
+ {/* ... */}
165
+ </ElevasisSystemsProvider>
166
+ ```
167
+
168
+ `KNOWLEDGE_ITEMS` is the exported default items array (matches the `CRM_ITEMS` shape from `@elevasis/ui/features/crm`). Spread it and append project-specific entries.
169
+
170
+ ### Replace (Project-Owned UI)
171
+
172
+ Skip `knowledgeManifest` entirely and build a project-owned route that calls `@elevasis/core/knowledge` directly. Use this when the project's knowledge UI has a different layout, navigation structure, or data sources than the platform default.
173
+
174
+ ```tsx
175
+ // ui/src/routes/knowledge/index.tsx
176
+ import { bySystem } from '@elevasis/core/knowledge'
177
+ import { useElevasisSystems } from '@elevasis/ui'
178
+
179
+ function MyCustomKnowledgeView() {
180
+ const { graph } = useElevasisSystems()
181
+ const nodes = bySystem(graph, 'sales.crm')
182
+ return <MyOwnLayout nodes={nodes} />
183
+ }
184
+ ```
185
+
186
+ The project owns the renderer, layout, search, and navigation. The data layer is shared -- the org model remains the source of truth, and query results are consistent with what `elevasis-sdk knowledge:*` returns at the CLI.
187
+
188
+ The `knowledgePlugin()` Vite plugin is still needed in this path because it generates the `KNOWLEDGE_BODIES` component map that any project-local renderer will need to display MDX bodies. The plugin is included automatically via `elevasisVite()` in the template's `vite.config.ts`.
189
+
190
+ ## Exports Reference
191
+
192
+ | Export | Package | Purpose |
193
+ | -------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------- |
194
+ | `elevasisVite` | `@elevasis/ui/vite` | Umbrella plugin factory; includes `knowledgePlugin` |
195
+ | `knowledgeManifest` | `@elevasis/ui/features/knowledge` | Default `SystemModule` manifest; spread or pass directly |
196
+ | `KnowledgeSidebar` | `@elevasis/ui/features/knowledge` | Default sidebar wrapper |
197
+ | `KnowledgeSidebarMiddle` | `@elevasis/ui/features/knowledge` | Sidebar middle section; accepts `items?: NavItem[]` |
198
+ | `KNOWLEDGE_ITEMS` | `@elevasis/ui/knowledge` | Default sidebar nav items array |
199
+ | `KnowledgeBrowser` | `@elevasis/ui/knowledge` | Composed browser: search bar + detail view |
200
+ | `KnowledgeTree` | `@elevasis/ui/knowledge` | Tree for one mount axis |
201
+ | `KnowledgeNodeList` | `@elevasis/ui/knowledge` | Flat list of node cards |
202
+ | `KnowledgeNodeView` | `@elevasis/ui/knowledge` | Single node: title, kind badge, body, edge sidecar |
203
+ | `KnowledgeSearchBar` | `@elevasis/ui/knowledge` | FlexSearch over title, summary, and body |
204
+ | `KnowledgeMDXProvider` | `@elevasis/ui/knowledge` | React context supplying the component allowlist |
205
+ | `knowledgePlugin` | `@elevasis/ui/vite-plugin-knowledge` | Vite plugin for build-time MDX codegen + HMR (direct use) |
206
+ | `bySystem`, `byKind`, `byOwner`, `governs`, `governedBy` | `@elevasis/core/knowledge` | Pure query functions for project-owned custom UI |
207
+
208
+ For template-derived projects, import `elevasisVite` from `@elevasis/ui/vite` rather than `knowledgePlugin` directly. The direct `knowledgePlugin` import from `@elevasis/ui/vite-plugin-knowledge` remains available for advanced or non-template wiring.
209
+
210
+ ## Decision Tree
211
+
212
+ - **Just want knowledge nodes to show up?** Author `.mdx` files under `core/config/knowledge/nodes/`. That is it.
213
+ - **Need extra sidebar nav entries or a different items order?** Spread the manifest, override `sidebar` with a composed `KnowledgeSidebarMiddle` using custom `items`.
214
+ - **Need a completely different layout, data sources, or knowledge UX?** Skip the manifest, own the route, call `@elevasis/core/knowledge` directly.
215
+ - **Need to extend the MDX component allowlist for custom body components?** Pass `extraComponents` to `KnowledgeMDXProvider` in your custom renderer.
216
+ - **Need to add a 6th segment to the sidebar strip?** See the SegmentedControl extension section below.
217
+ - **Need a custom main-pane dispatcher?** See the DescribeNodeView section below.
218
+
219
+ ## Phase 1.5 Extensions
220
+
221
+ Phase 1.5 adds two extension surfaces on top of the customization tiers above: a mount-axis `SegmentedControl` strip in the sidebar and a `DescribeNodeView` dispatcher in the main pane. Both are composable -- you can extend the defaults or replace them entirely.
222
+
223
+ ### Extending the SegmentedControl (add a 6th segment)
224
+
225
+ Phase 1.5 ships `KnowledgeSidebarMiddle` with a five-segment strip above the search bar:
226
+
227
+ ```
228
+ [ By System ] [ By Kind ] [ By Owner ] [ Governs ] [ Governed By ]
229
+ ```
230
+
231
+ Each segment maps to a mount axis exposed by `@elevasis/core/knowledge`. The strip is a `SegmentedControl` from `@mantine/core`; selected axis is local sidebar state and does NOT affect the URL.
232
+
233
+ To add a 6th segment, supply a `segments` prop to `KnowledgeSidebarMiddle`:
234
+
235
+ ```tsx
236
+ import {
237
+ KnowledgeSidebar,
238
+ KnowledgeSidebarMiddle,
239
+ KNOWLEDGE_SEGMENTS,
240
+ } from '@elevasis/ui/knowledge'
241
+ import { knowledgeManifest } from '@elevasis/ui/features/knowledge'
242
+ import { byOwner } from '@elevasis/core/knowledge'
243
+
244
+ // KNOWLEDGE_SEGMENTS is the default five-item array; spread and append.
245
+ const customSegments = [
246
+ ...KNOWLEDGE_SEGMENTS,
247
+ {
248
+ value: 'by-team',
249
+ label: 'By Team',
250
+ // renderBody receives (graph, knowledgeNodes, selectedNodeId, onSelectNode).
251
+ // Return any ReactNode -- the strip swaps the tree area for your component.
252
+ renderBody: ({ graph, knowledgeNodes, onSelectNode, selectedNodeId }) => {
253
+ const teamNodes = byOwner(graph, 'team:product', knowledgeNodes)
254
+ return (
255
+ <MyTeamList
256
+ nodes={teamNodes}
257
+ onSelect={onSelectNode}
258
+ activeId={selectedNodeId}
259
+ />
260
+ )
261
+ },
262
+ },
263
+ ]
264
+
265
+ const CustomKnowledgeSidebar = () => (
266
+ <KnowledgeSidebar>
267
+ <KnowledgeSidebarMiddle segments={customSegments} />
268
+ </KnowledgeSidebar>
269
+ )
270
+
271
+ export const customKnowledgeManifest = {
272
+ ...knowledgeManifest,
273
+ sidebar: CustomKnowledgeSidebar,
274
+ }
275
+ ```
276
+
277
+ Rules and constraints:
278
+
279
+ - `value` must be unique across all segments in the array.
280
+ - `label` is the display string inside the `SegmentedControl`; keep it short (under 10 characters) to fit the 320 px sidebar width.
281
+ - `renderBody` receives the same props as the built-in axis renderers. The tree area is replaced by whatever the function returns while that segment is active.
282
+ - The first segment in the array is the default selection on mount.
283
+ - Segment selection is reset to the first item whenever the user navigates to `/knowledge/command-view*` (the command-view sub-route bypasses the strip entirely and renders `CommandViewSidebarContent` instead).
284
+
285
+ ### Replacing `DescribeNodeView` Entirely
286
+
287
+ Phase 1.5 introduces `DescribeNodeView` as the main-pane dispatcher. It receives any graph node (not just knowledge nodes) and routes to a per-kind view component:
288
+
289
+ ```tsx
290
+ function DescribeNodeView({ node, graph, onNavigateToNode }) {
291
+ switch (node.kind) {
292
+ case 'knowledge': return <KnowledgeNodeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
293
+ case 'system': return <SystemDescribeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
294
+ case 'resource': return <ResourceDescribeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
295
+ case 'organization': return <OrganizationDescribeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
296
+ default: return <GenericDescribeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
297
+ }
298
+ }
299
+ ```
300
+
301
+ **Keep sidebar chrome, replace main pane:** Override the route component in your project's route tree. The default route for `/knowledge/:nodeId` renders `DescribeNodeView`. Replace it with a project-owned component that receives the same `node` and `graph` props:
302
+
303
+ ```tsx
304
+ // ui/src/routes/knowledge/$nodeId.tsx
305
+ import { useParams } from '@tanstack/react-router'
306
+ import { useElevasisSystems } from '@elevasis/ui'
307
+
308
+ export default function KnowledgeNodeRoute() {
309
+ const { nodeId } = useParams({ from: '/knowledge/$nodeId' })
310
+ const { graph } = useElevasisSystems()
311
+ const node = graph.nodes.find((n) => n.id === nodeId)
312
+
313
+ if (!node) return <MyNotFoundView />
314
+
315
+ // Completely custom dispatcher -- no platform chrome in the main pane.
316
+ return <MyDescribeNodeView node={node} graph={graph} />
317
+ }
318
+ ```
319
+
320
+ The sidebar (managed by the manifest) continues to operate normally. Tree clicks still navigate to `/knowledge/:nodeId`. Only the main pane changes.
321
+
322
+ **Own everything:** Skip `knowledgeManifest` and build your own route tree as described in the Replace section above. Call `@elevasis/core/knowledge` directly for data and supply your own dispatcher.
323
+
324
+ ### Overriding Per-Kind Views (extend the dispatcher's switch)
325
+
326
+ If you want the default dispatcher behavior for most kinds but need a custom layout for one kind, extend the exported `DescribeNodeView` rather than replacing it entirely. Phase 1.5 exports `createDescribeNodeDispatcher` for this purpose:
327
+
328
+ ```tsx
329
+ import {
330
+ createDescribeNodeDispatcher,
331
+ SystemDescribeView,
332
+ } from '@elevasis/ui/knowledge'
333
+
334
+ // Supply overrides for specific kinds; all others fall through to platform defaults.
335
+ const MyDescribeNodeView = createDescribeNodeDispatcher({
336
+ system: ({ node, graph, onNavigateToNode }) => (
337
+ // Project-specific System view with extra metadata section.
338
+ <MyFeatureDetailView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
339
+ ),
340
+ // 'knowledge', 'resource', 'organization', and the default fallback
341
+ // are handled by the platform unless you override them here.
342
+ })
343
+ ```
344
+
345
+ `createDescribeNodeDispatcher` returns a component with the same props interface as `DescribeNodeView` (`node`, `graph`, `onNavigateToNode`). You can drop it anywhere the default dispatcher is used.
346
+
347
+ Override keys match `OrgGraphNodeKind` values: `'knowledge'`, `'feature'`, `'resource'`, `'organization'`, `'surface'`, `'entity'`, `'action'`. The `default` key overrides the generic fallback for unknown kinds.
348
+
349
+ Each override function receives `{ node, graph, onNavigateToNode }` and must return a `ReactNode`. The platform kind-specific components (`KnowledgeNodeView`, `SystemDescribeView`, etc.) are all exported from `@elevasis/ui/knowledge` so you can compose them inside your override rather than replacing them from scratch:
350
+
351
+ ```tsx
352
+ const MyDescribeNodeView = createDescribeNodeDispatcher({
353
+ system: ({ node, graph, onNavigateToNode }) => (
354
+ <>
355
+ {/* Platform view for the standard fields */}
356
+ <SystemDescribeView node={node} graph={graph} onNavigateToNode={onNavigateToNode} />
357
+ {/* Project-specific extension panel below */}
358
+ <MySystemAuditPanel systemId={node.id} />
359
+ </>
360
+ ),
361
+ })
362
+ ```
363
+
364
+ ### Phase 1.5 Exports Reference
365
+
366
+ The following exports are added in Phase 1.5 on top of the exports table above:
367
+
368
+ | Export | Package | Purpose |
369
+ | ------------------------------ | ------------------------ | ---------------------------------------------------------------------------- |
370
+ | `DescribeNodeView` | `@elevasis/ui/knowledge` | Default graph-node dispatcher; routes by `node.kind` |
371
+ | `createDescribeNodeDispatcher` | `@elevasis/ui/knowledge` | Factory for per-kind overrides; returns a `DescribeNodeView`-shape component |
372
+ | `SystemDescribeView` | `@elevasis/ui/knowledge` | Minimal System node view: path, icon, lifecycle, hierarchy, edges |
373
+ | `ResourceDescribeView` | `@elevasis/ui/knowledge` | Minimal resource node view: resourceType, description, edges |
374
+ | `OrganizationDescribeView` | `@elevasis/ui/knowledge` | Minimal organization node view: label, edges |
375
+ | `GenericDescribeView` | `@elevasis/ui/knowledge` | Key/value fallback for unknown kinds |
376
+ | `KNOWLEDGE_SEGMENTS` | `@elevasis/ui/knowledge` | Default five-segment array for `KnowledgeSidebarMiddle` |
377
+
378
+ `KnowledgeSidebarMiddle` gains an optional `segments?: KnowledgeSegment[]` prop (defaults to `KNOWLEDGE_SEGMENTS`). The `KnowledgeSegment` type is exported from `@elevasis/ui/knowledge`.
379
+
380
+ ## See Also
381
+
382
+ - [Composition and Extensibility](../composition-extensibility.mdx) -- the general sidebar override pattern this recipe follows (CRM + delivery examples)
383
+ - [Query the Knowledge Graph](query-the-knowledge-graph.md) -- CLI walkthrough of the same five mount axes
384
+ - [Contracts Reference](../reference/contracts.md) -- `SystemModule`, `NavItem`, `OrgKnowledgeNode` TypeScript shapes
@@ -1,14 +1,14 @@
1
- ---
2
- title: Customize organization-model.ts
3
- description: Annotated walkthrough for customizing the flat Organization Model in template-derived projects.
4
- ---
5
1
  <!-- @generated by packages/sdk/scripts/copy-reference-docs.mjs -- DO NOT EDIT -->
6
2
  <!-- Regenerate: pnpm scaffold:sync -->
7
3
 
4
+ ---
5
+ title: Customize organization-model.ts
6
+ description: Annotated walkthrough for customizing the System-backed Organization Model in template-derived projects.
7
+ ---
8
8
 
9
9
  # Customize organization-model.ts
10
10
 
11
- `core/config/organization-model.ts` is the semantic contract between the UI shell and platform operations. The shell reads one flat feature list, derives hierarchy from dotted IDs, and binds resources through graph links declared on resource metadata.
11
+ `core/config/organization-model.ts` is the semantic contract between the UI shell and platform operations. The shell reads the id-keyed `systems` map for semantic ownership and access, reads `navigation.sidebar` for shell navigation, and binds resources through the id-keyed `resources` map.
12
12
 
13
13
  ## Imports
14
14
 
@@ -24,61 +24,89 @@ import {
24
24
  - `createFoundationOrganizationModel` resolves defaults and returns the canonical model plus UI-facing helpers.
25
25
  - `OrganizationModel` is the fully resolved model type.
26
26
 
27
- ## Features
27
+ ## Systems
28
28
 
29
- The `features` array is the source of truth for navigation, labels, enabled state, admin visibility, and development-only visibility.
29
+ The `systems` map is the source of truth for semantic hierarchy, lifecycle, admin visibility, and governed ownership.
30
30
 
31
31
  ```ts
32
32
  const override = defineOrganizationModel({
33
- features: [
34
- {
33
+ systems: {
34
+ dashboard: {
35
35
  id: 'dashboard',
36
+ order: 10,
36
37
  label: 'Dashboard',
37
- enabled: true,
38
- path: '/',
39
- icon: 'feature.dashboard',
40
- uiPosition: 'sidebar-primary'
38
+ lifecycle: 'active',
39
+ description: 'Command Center home'
41
40
  },
42
- {
41
+ sales: {
43
42
  id: 'sales',
43
+ order: 20,
44
44
  label: 'Sales',
45
- enabled: true,
46
- icon: 'feature.sales',
47
- uiPosition: 'sidebar-primary'
45
+ lifecycle: 'active'
48
46
  },
49
- {
47
+ 'sales.crm': {
50
48
  id: 'sales.crm',
49
+ order: 30,
51
50
  label: 'CRM',
52
- enabled: true,
53
- path: '/crm'
54
- },
55
- {
56
- id: 'admin',
57
- label: 'Admin',
58
- enabled: true,
59
- path: '/admin',
60
- uiPosition: 'sidebar-bottom',
61
- requiresAdmin: true
51
+ parentSystemId: 'sales',
52
+ lifecycle: 'active',
53
+ description: 'CRM pipeline and deal operations'
62
54
  }
63
- ]
55
+ },
56
+ navigation: {
57
+ sidebar: {
58
+ primary: {
59
+ dashboard: {
60
+ type: 'surface',
61
+ order: 10,
62
+ label: 'Dashboard',
63
+ path: '/',
64
+ surfaceType: 'dashboard',
65
+ icon: 'feature.dashboard',
66
+ targets: { systems: ['dashboard'] }
67
+ },
68
+ business: {
69
+ type: 'group',
70
+ order: 20,
71
+ label: 'Business',
72
+ children: {
73
+ crm: {
74
+ type: 'surface',
75
+ order: 10,
76
+ label: 'CRM',
77
+ path: '/crm',
78
+ surfaceType: 'page',
79
+ targets: { systems: ['sales.crm'] }
80
+ }
81
+ }
82
+ }
83
+ },
84
+ bottom: {}
85
+ }
86
+ }
64
87
  })
65
88
  ```
66
89
 
67
- Feature field reference:
90
+ System field reference:
68
91
 
69
- - `id` -- lowercase dotted path. Parent features are inferred from prefix segments.
92
+ - `id` -- lowercase dotted path. Parent Systems are inferred from prefix segments or declared through `parentSystemId`.
93
+ - `order` -- deterministic map iteration order. Use multiples of 10 for easy insertion.
70
94
  - `label` -- sidebar and breadcrumb label.
71
95
  - `description` -- optional settings/help text.
72
- - `enabled` -- organization default.
73
- - `path` -- route path for leaf nodes. Containers omit it.
74
- - `icon` and `color` -- optional display metadata. Use semantic icon tokens such as `feature.dashboard`, `feature.sales`, or project-owned `custom.*` tokens; UI icon libraries are implementation details.
75
- - `uiPosition` -- `sidebar-primary` or `sidebar-bottom`; descendants inherit it.
96
+ - `kind` -- product, operational, platform, or diagnostic.
97
+ - `parentSystemId` -- explicit parent System link.
98
+ - `lifecycle` -- draft, beta, active, deprecated, or archived.
99
+ - `ui` -- optional route metadata used by shell matching during migration.
76
100
  - `requiresAdmin` -- hides the node for non-admin members; descendants inherit it.
77
- - `devOnly` -- hides the node outside development contexts; descendants inherit it.
101
+ - `actions` / `policies` -- references to cross-cutting domains.
102
+
103
+ ## Sidebar Navigation
104
+
105
+ Author shell navigation under `navigation.sidebar`. Groups can contain nested nodes; routeable surface leaves provide `path`, `surfaceType`, and `targets`. Dashboard should appear before Business, Business is a navigation group only, and `/clients` is the canonical clients route.
78
106
 
79
107
  ## Resource Binding
80
108
 
81
- Resource identity and governance metadata live in `OrganizationModel` under `resources.entries`. Workflows, agents, and integrations import those descriptors and derive runtime `resourceId` / `type` from them while still declaring semantic graph links in resource metadata.
109
+ Resource identity and governance metadata live in `OrganizationModel` under `resources`. Workflows, agents, integrations, and scripts import those descriptors and derive runtime `resourceId` / `type` from them. The graph derives System membership from `ResourceEntry.systemPath`.
82
110
 
83
111
  ```ts
84
112
  // core/config/organization-model.ts
@@ -87,8 +115,9 @@ import { defineResources } from '@elevasis/core/organization-model'
87
115
  export const resourceDescriptors = defineResources({
88
116
  leadImport: {
89
117
  id: 'lead-import',
118
+ order: 10,
90
119
  kind: 'workflow',
91
- systemId: 'sys.prospecting',
120
+ systemPath: 'sales.crm',
92
121
  ownerRoleId: 'role-ops-lead',
93
122
  status: 'active'
94
123
  }
@@ -102,17 +131,16 @@ config: {
102
131
  type: resourceDescriptors.leadImport.kind,
103
132
  version: '1.0.0',
104
133
  status: 'prod',
105
- links: [{ nodeId: 'feature:sales.lead-gen', kind: 'operates-on' }],
106
134
  category: 'production'
107
135
  }
108
136
  ```
109
137
 
110
138
  Use kind-prefixed graph IDs for cross-collection links:
111
139
 
112
- - `feature:sales.crm`
140
+ - `system:sales.crm`
113
141
  - `integration:instantly`
114
142
  - `resource:lead-import`
115
- - `capability:operations.queue.review`
143
+ - `action:operations.queue.review`
116
144
 
117
145
  `category` is one of `production`, `diagnostic`, `internal`, or `testing`.
118
146
 
@@ -150,10 +178,10 @@ export const organizationModel = foundation.model
150
178
  export const { getOrganizationSurface } = foundation
151
179
  ```
152
180
 
153
- Pass `canonicalOrganizationModel` to `ElevasisFeaturesProvider` in `ui/src/routes/__root.tsx`.
181
+ Pass `canonicalOrganizationModel` to `ElevasisSystemsProvider` in `ui/src/routes/__root.tsx`.
154
182
 
155
183
  ## Resolve Behavior
156
184
 
157
- `createFoundationOrganizationModel(override)` resolves defaults, validates feature hierarchy, and exposes helper functions used by the shell. Arrays are replaced wholesale, so if you provide `features`, include every feature the app should expose.
185
+ `createFoundationOrganizationModel(override)` resolves defaults, validates System hierarchy, and exposes helper functions used by the shell. Id-keyed domain maps merge additively by key, so tenant overrides can add one System or resource without re-authoring every default entry.
158
186
 
159
- Validation catches duplicate feature IDs, missing parent containers, invalid graph IDs, and invalid sidebar positions.
187
+ Validation catches duplicate System IDs, missing parent Systems, invalid graph IDs, and invalid UI paths.