@elevasis/ui 2.31.0 → 2.32.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 (144) hide show
  1. package/dist/{CoreAuthKitInner-KSEGSB67.js → CoreAuthKitInner-QC62UHTZ.js} +1 -1
  2. package/dist/api/index.js +3 -3
  3. package/dist/app/index.css +38 -0
  4. package/dist/app/index.d.ts +69 -9
  5. package/dist/app/index.js +7 -6
  6. package/dist/auth/context.js +1 -1
  7. package/dist/auth/index.js +1 -1
  8. package/dist/charts/index.js +5 -6
  9. package/dist/{chunk-XQHZBA65.js → chunk-2RJMVWFJ.js} +1 -6
  10. package/dist/{chunk-CW3UNAF2.js → chunk-4DYOXEH6.js} +410 -5
  11. package/dist/{chunk-HQGF4ATG.js → chunk-4MFNGNHF.js} +118 -141
  12. package/dist/{chunk-ND42LPY4.js → chunk-4QK76KIF.js} +6 -6
  13. package/dist/chunk-5FJJ72HU.js +13 -0
  14. package/dist/chunk-5J4PDX26.js +112 -0
  15. package/dist/{chunk-QDEETKYT.js → chunk-6DWD423K.js} +9 -9
  16. package/dist/{chunk-SHQXMW4F.js → chunk-7KZINJLP.js} +46 -28
  17. package/dist/{chunk-L3BVJWML.js → chunk-EPTHX4VZ.js} +1 -1
  18. package/dist/{chunk-JKSUN5GN.js → chunk-GCOQ3TBG.js} +81 -746
  19. package/dist/{chunk-DZTG5IAC.js → chunk-I2KLQ2HA.js} +1 -7
  20. package/dist/{chunk-L2NVFLXU.js → chunk-IQHU7O5Y.js} +4 -4
  21. package/dist/{chunk-P55BJZZW.js → chunk-IZWTVFJ2.js} +16 -4
  22. package/dist/{chunk-QHEWXU7I.js → chunk-JFL3GRD4.js} +1 -1
  23. package/dist/{chunk-Q6OYNEGR.js → chunk-LLRXA7D7.js} +5 -6
  24. package/dist/{chunk-7KC4P3AU.js → chunk-MOY4VOHF.js} +2 -12
  25. package/dist/{chunk-XQQEKWTL.js → chunk-N55DVMAG.js} +6 -2
  26. package/dist/{chunk-TOIXUWR6.js → chunk-ND5TDV2J.js} +1 -1
  27. package/dist/{chunk-WF227UBV.js → chunk-QQHOKTJA.js} +4 -4
  28. package/dist/{chunk-T3IPHEYJ.js → chunk-QTI3KC7D.js} +4335 -554
  29. package/dist/chunk-QXCDKE2O.js +486 -0
  30. package/dist/{chunk-3BAPR3KA.js → chunk-RQA2EVN3.js} +5 -15
  31. package/dist/{chunk-HYNYEBHM.js → chunk-RQTWIXJ5.js} +3 -3
  32. package/dist/chunk-T35FWDAB.js +4342 -0
  33. package/dist/{chunk-DWK2QIAK.js → chunk-TYRUKGGD.js} +1 -1
  34. package/dist/{chunk-GRDLB6LM.js → chunk-UROTM5OR.js} +13 -1
  35. package/dist/{chunk-6YT4IKJ7.js → chunk-VNAZTCHA.js} +15 -0
  36. package/dist/{chunk-5LJAEZMA.js → chunk-VRNMNB3O.js} +5 -6
  37. package/dist/chunk-WQPX44YM.js +1626 -0
  38. package/dist/{chunk-7HMCB26R.js → chunk-XZGSCABI.js} +1 -1
  39. package/dist/chunk-YLQEVSOR.js +299 -0
  40. package/dist/{chunk-Y4FWCG7Y.js → chunk-ZQOKIGZP.js} +8 -7
  41. package/dist/components/chat/index.js +1 -1
  42. package/dist/components/index.css +38 -0
  43. package/dist/components/index.d.ts +152 -50
  44. package/dist/components/index.js +36 -39
  45. package/dist/components/navigation/index.css +38 -0
  46. package/dist/components/navigation/index.js +4 -3
  47. package/dist/execution/index.d.ts +7 -2
  48. package/dist/execution/index.js +1 -1
  49. package/dist/features/auth/index.css +38 -0
  50. package/dist/features/auth/index.d.ts +91 -14
  51. package/dist/features/auth/index.js +42 -10
  52. package/dist/features/clients/index.css +38 -0
  53. package/dist/features/clients/index.d.ts +1 -1
  54. package/dist/features/clients/index.js +16 -15
  55. package/dist/features/crm/index.css +38 -0
  56. package/dist/features/crm/index.d.ts +80 -18
  57. package/dist/features/crm/index.js +16 -15
  58. package/dist/features/dashboard/index.css +38 -0
  59. package/dist/features/dashboard/index.d.ts +65 -25
  60. package/dist/features/dashboard/index.js +16 -16
  61. package/dist/features/delivery/index.css +38 -0
  62. package/dist/features/delivery/index.d.ts +80 -18
  63. package/dist/features/delivery/index.js +15 -15
  64. package/dist/features/knowledge/index.css +38 -0
  65. package/dist/features/knowledge/index.d.ts +20 -18
  66. package/dist/features/knowledge/index.js +112 -597
  67. package/dist/features/lead-gen/index.css +38 -0
  68. package/dist/features/lead-gen/index.d.ts +45 -43
  69. package/dist/features/lead-gen/index.js +16 -16
  70. package/dist/features/monitoring/index.css +38 -0
  71. package/dist/features/monitoring/index.d.ts +20 -18
  72. package/dist/features/monitoring/index.js +17 -17
  73. package/dist/features/monitoring/requests/index.css +38 -0
  74. package/dist/features/monitoring/requests/index.d.ts +21 -19
  75. package/dist/features/monitoring/requests/index.js +15 -14
  76. package/dist/features/operations/index.css +38 -0
  77. package/dist/features/operations/index.d.ts +930 -66
  78. package/dist/features/operations/index.js +21 -24
  79. package/dist/features/seo/index.d.ts +20 -18
  80. package/dist/features/seo/index.js +2 -2
  81. package/dist/features/settings/index.css +38 -0
  82. package/dist/features/settings/index.d.ts +80 -18
  83. package/dist/features/settings/index.js +16 -15
  84. package/dist/graph/index.js +1 -1
  85. package/dist/hooks/delivery/index.css +38 -0
  86. package/dist/hooks/delivery/index.d.ts +60 -0
  87. package/dist/hooks/delivery/index.js +3 -3
  88. package/dist/hooks/index.css +38 -0
  89. package/dist/hooks/index.d.ts +301 -87
  90. package/dist/hooks/index.js +14 -13
  91. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +143 -33
  92. package/dist/hooks/operations/command-view/utils/transformCommandViewData.js +1 -1
  93. package/dist/hooks/published.css +38 -0
  94. package/dist/hooks/published.d.ts +301 -87
  95. package/dist/hooks/published.js +14 -13
  96. package/dist/index.css +38 -0
  97. package/dist/index.d.ts +976 -1341
  98. package/dist/index.js +15 -14
  99. package/dist/initialization/index.d.ts +60 -0
  100. package/dist/initialization/index.js +1 -1
  101. package/dist/knowledge/index.d.ts +809 -1160
  102. package/dist/knowledge/index.js +5988 -2140
  103. package/dist/{chunk-O2QOPJI5.js → knowledge-search-index-5KYPO746.js} +96 -852
  104. package/dist/layout/index.js +3 -4
  105. package/dist/organization/index.css +38 -0
  106. package/dist/organization/index.js +1 -1
  107. package/dist/profile/index.d.ts +60 -0
  108. package/dist/profile/index.js +1 -1
  109. package/dist/provider/ElevasisServiceContext.js +1 -1
  110. package/dist/provider/index.css +38 -0
  111. package/dist/provider/index.d.ts +786 -1249
  112. package/dist/provider/index.js +11 -10
  113. package/dist/provider/published.css +38 -0
  114. package/dist/provider/published.d.ts +783 -1246
  115. package/dist/provider/published.js +8 -7
  116. package/dist/router/context.js +1 -1
  117. package/dist/router/index.js +1 -1
  118. package/dist/sse/index.js +1 -1
  119. package/dist/supabase/index.d.ts +117 -0
  120. package/dist/supabase/index.js +1 -1
  121. package/dist/test-utils/index.d.ts +16 -9
  122. package/dist/test-utils/index.js +40 -33
  123. package/dist/test-utils/setup-integration.js +1 -1
  124. package/dist/test-utils/setup.js +1 -1
  125. package/dist/theme/index.js +3 -3
  126. package/dist/theme/presets/index.js +1 -1
  127. package/dist/typeform/index.js +1 -1
  128. package/dist/typeform/schemas.js +1 -1
  129. package/dist/types/index.d.ts +205 -35
  130. package/dist/utils/index.d.ts +65 -25
  131. package/dist/utils/index.js +2 -2
  132. package/dist/vite/index.js +1 -1
  133. package/dist/vite-plugin-knowledge/index.js +1 -1
  134. package/dist/zustand/index.js +1 -1
  135. package/package.json +39 -38
  136. package/src/provider/README.md +5 -5
  137. package/dist/chunk-542WPQU2.js +0 -413
  138. package/dist/chunk-6IXOKUBC.js +0 -347
  139. package/dist/chunk-CQZ3DNQY.js +0 -740
  140. package/dist/chunk-ECNNI3NT.js +0 -6
  141. package/dist/chunk-JDNEWB5F.js +0 -10
  142. package/dist/chunk-MVFCLZSK.js +0 -4337
  143. package/dist/chunk-OAVTMITG.js +0 -13
  144. package/dist/chunk-TVRQ6AQI.js +0 -476
@@ -1,775 +1,4 @@
1
- import { SemanticIcon } from './chunk-GRDLB6LM.js';
2
- import { Stack, Group, Title, Text, Box, Divider, useTree, Tree, UnstyledButton, TextInput } from '@mantine/core';
3
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { useMemo, useState, useRef, useEffect } from 'react';
5
- import { useClipboard } from '@mantine/hooks';
6
- import { IconChevronDown, IconChevronRight, IconX, IconSearch, IconCheck, IconCopy } from '@tabler/icons-react';
7
-
8
- // src/knowledge/iconTokens.ts
9
- var KNOWLEDGE_ICON_TOKEN_BY_KIND = {
10
- playbook: "knowledge.playbook",
11
- strategy: "knowledge.strategy",
12
- reference: "knowledge.reference"
13
- };
14
- function getKnowledgeIconToken(node) {
15
- return node.icon ?? KNOWLEDGE_ICON_TOKEN_BY_KIND[node.kind];
16
- }
17
-
18
- // ../core/src/knowledge/queries.ts
19
- function buildKnowledgeSourceIdMap(graph) {
20
- const map = /* @__PURE__ */ new Map();
21
- for (const node of graph.nodes) {
22
- if (node.kind === "knowledge" && node.sourceId) {
23
- map.set(node.id, node.sourceId);
24
- }
25
- }
26
- return map;
27
- }
28
- function byFeature(graph, featureId, knowledgeNodes) {
29
- const targetGraphNodeId = `feature:${featureId}`;
30
- const governingKnowledgeNodeIds = /* @__PURE__ */ new Set();
31
- for (const edge of graph.edges) {
32
- if (edge.kind === "governs" && edge.targetId === targetGraphNodeId && edge.sourceId.startsWith("knowledge:")) {
33
- governingKnowledgeNodeIds.add(edge.sourceId);
34
- }
35
- }
36
- const sourceIdMap = buildKnowledgeSourceIdMap(graph);
37
- const matchingOmIds = /* @__PURE__ */ new Set();
38
- for (const graphNodeId of governingKnowledgeNodeIds) {
39
- const omId = sourceIdMap.get(graphNodeId);
40
- if (omId) matchingOmIds.add(omId);
41
- }
42
- return knowledgeNodes.filter((n) => matchingOmIds.has(n.id));
43
- }
44
- function byKind(_graph, kind, knowledgeNodes) {
45
- return knowledgeNodes.filter((n) => n.kind === kind);
46
- }
47
- var KIND_CHIP_TONE_STYLES = {
48
- subtle: {
49
- backgroundColor: "var(--color-surface-hover)",
50
- borderColor: "var(--color-border)",
51
- color: "var(--color-text-dimmed)"
52
- },
53
- primary: {
54
- backgroundColor: "var(--surface-primary-subtle)",
55
- borderColor: "color-mix(in srgb, var(--color-primary) 28%, var(--color-border))",
56
- color: "var(--color-primary)"
57
- },
58
- muted: {
59
- backgroundColor: "var(--color-surface)",
60
- borderColor: "var(--color-border)",
61
- color: "var(--color-text-subtle)"
62
- }
63
- };
64
- function KindChip({ kind, tone = "subtle", style, ...spanProps }) {
65
- return /* @__PURE__ */ jsx(
66
- "span",
67
- {
68
- ...spanProps,
69
- "data-kind-chip": true,
70
- "data-tone": tone,
71
- style: {
72
- display: "inline-flex",
73
- alignItems: "center",
74
- width: "fit-content",
75
- maxWidth: "100%",
76
- padding: "2px 8px",
77
- border: "1px solid",
78
- borderRadius: "var(--mantine-radius-sm)",
79
- fontFamily: "var(--mantine-font-family)",
80
- fontSize: "var(--mantine-font-size-xs)",
81
- fontWeight: 600,
82
- lineHeight: 1.2,
83
- letterSpacing: 0,
84
- whiteSpace: "nowrap",
85
- transition: "background-color var(--duration-fast) var(--easing), border-color var(--duration-fast) var(--easing)",
86
- ...KIND_CHIP_TONE_STYLES[tone],
87
- ...style
88
- },
89
- children: kind
90
- }
91
- );
92
- }
93
- function NodeHeader({
94
- title,
95
- kind,
96
- tone = "primary",
97
- iconToken,
98
- description,
99
- updatedAt,
100
- rightSection
101
- }) {
102
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
103
- /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "flex-start", wrap: "nowrap", children: [
104
- iconToken && /* @__PURE__ */ jsx(
105
- SemanticIcon,
106
- {
107
- token: iconToken,
108
- fallbackKind: "knowledge",
109
- size: 22,
110
- style: { color: "var(--color-primary)", marginTop: 5 }
111
- }
112
- ),
113
- /* @__PURE__ */ jsx(Title, { order: 3, style: { flex: 1, minWidth: 0, color: "var(--color-text)" }, children: title }),
114
- /* @__PURE__ */ jsx(KindChip, { kind, tone, style: { flexShrink: 0, marginTop: 4 } }),
115
- rightSection
116
- ] }),
117
- description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", style: { lineHeight: 1.5 }, children: description }),
118
- updatedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", style: { opacity: 0.7 }, children: [
119
- "Updated ",
120
- updatedAt
121
- ] })
122
- ] });
123
- }
124
- function EdgeChip({ id, onClick }) {
125
- return /* @__PURE__ */ jsx(
126
- "div",
127
- {
128
- role: onClick ? "button" : void 0,
129
- tabIndex: onClick ? 0 : void 0,
130
- onClick,
131
- onKeyDown: onClick ? (e) => (e.key === "Enter" || e.key === " ") && onClick() : void 0,
132
- style: {
133
- display: "inline-flex",
134
- alignItems: "center",
135
- padding: "2px 8px",
136
- borderRadius: "var(--mantine-radius-sm)",
137
- backgroundColor: "var(--color-surface)",
138
- border: "1px solid var(--color-border)",
139
- fontSize: "var(--mantine-font-size-xs)",
140
- color: onClick ? "var(--color-primary)" : "var(--color-text-subtle)",
141
- cursor: onClick ? "pointer" : "default",
142
- fontFamily: "var(--mantine-font-family-monospace)",
143
- width: "fit-content",
144
- background: "none"
145
- },
146
- children: id
147
- }
148
- );
149
- }
150
- function EdgeGroup({ label, ids, onNavigateToNode }) {
151
- return /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
152
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 500, children: label }),
153
- ids.map((id) => /* @__PURE__ */ jsx(EdgeChip, { id, onClick: onNavigateToNode ? () => onNavigateToNode(id) : void 0 }, id))
154
- ] });
155
- }
156
- function knowledgeNodeIdFromGraphNode(graphNode, graphNodeId) {
157
- if (graphNode?.sourceId) return graphNode.sourceId;
158
- return graphNodeId.startsWith("knowledge:") ? graphNodeId.slice("knowledge:".length) : graphNodeId;
159
- }
160
- function RelatedKnowledgeSection({
161
- nodeId,
162
- graph,
163
- knowledgeNodes,
164
- onNavigateToNode
165
- }) {
166
- const knowledgeById = new Map(knowledgeNodes.map((node) => [node.id, node]));
167
- const cards = graph.edges.filter((edge) => edge.kind === "governs" && edge.targetId === nodeId).map((edge) => {
168
- const graphNode = graph.nodes.find((node) => node.id === edge.sourceId && node.kind === "knowledge");
169
- const knowledgeNode = knowledgeById.get(knowledgeNodeIdFromGraphNode(graphNode, edge.sourceId));
170
- return knowledgeNode ? { graphNodeId: edge.sourceId, node: knowledgeNode } : null;
171
- }).filter((card) => card !== null);
172
- if (cards.length === 0) return null;
173
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", "data-related-knowledge-section": true, children: [
174
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, tt: "uppercase", c: "dimmed", style: { letterSpacing: "0.05em" }, children: "Governing Knowledge" }),
175
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: cards.map(({ graphNodeId, node }) => /* @__PURE__ */ jsx(
176
- Box,
177
- {
178
- component: onNavigateToNode ? "button" : "article",
179
- type: onNavigateToNode ? "button" : void 0,
180
- onClick: onNavigateToNode ? () => onNavigateToNode(graphNodeId) : void 0,
181
- style: {
182
- display: "block",
183
- width: "100%",
184
- padding: "var(--mantine-spacing-sm)",
185
- border: "1px solid var(--color-border)",
186
- borderRadius: "var(--mantine-radius-sm)",
187
- background: "var(--color-surface)",
188
- color: "var(--color-text)",
189
- textAlign: "left",
190
- cursor: onNavigateToNode ? "pointer" : "default",
191
- font: "inherit"
192
- },
193
- children: /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
194
- /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "flex-start", wrap: "nowrap", children: [
195
- /* @__PURE__ */ jsx(
196
- SemanticIcon,
197
- {
198
- token: getKnowledgeIconToken(node),
199
- fallbackKind: node.kind,
200
- size: 16,
201
- style: { color: "var(--color-text-subtle)", marginTop: 1 }
202
- }
203
- ),
204
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, style: { flex: 1, minWidth: 0, lineHeight: 1.35 }, children: node.title }),
205
- /* @__PURE__ */ jsx(KindChip, { kind: node.kind, tone: "muted", style: { flexShrink: 0 } })
206
- ] }),
207
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", style: { lineHeight: 1.45 }, children: node.summary })
208
- ] })
209
- },
210
- node.id
211
- )) })
212
- ] });
213
- }
214
- function relatedIds(graph, nodeId, edgeKind, direction, targetKind) {
215
- return graph.edges.filter(
216
- (edge) => direction === "outgoing" ? edge.kind === edgeKind && edge.sourceId === nodeId : edge.kind === edgeKind && edge.targetId === nodeId
217
- ).map((edge) => direction === "outgoing" ? edge.targetId : edge.sourceId).filter((id) => {
218
- if (!targetKind) return true;
219
- return graph.nodes.find((node) => node.id === id)?.kind === targetKind;
220
- });
221
- }
222
- function EdgeRelationshipGroup({ nodeId, graph, knowledgeNodes, onNavigateToNode }) {
223
- const subFeatures = relatedIds(graph, nodeId, "contains", "outgoing", "feature");
224
- const resourcesUsed = relatedIds(graph, nodeId, "uses", "outgoing", "resource");
225
- const entities = relatedIds(graph, nodeId, "operates-on", "outgoing", "entity");
226
- const governedTargets = relatedIds(graph, nodeId, "governs", "outgoing");
227
- const governingKnowledge = relatedIds(graph, nodeId, "governs", "incoming", "knowledge");
228
- const hasRelationships = subFeatures.length > 0 || resourcesUsed.length > 0 || entities.length > 0 || governedTargets.length > 0 || governingKnowledge.length > 0;
229
- if (!hasRelationships) return null;
230
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", "data-edge-relationship-group": true, children: [
231
- /* @__PURE__ */ jsx(Divider, {}),
232
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, tt: "uppercase", c: "dimmed", style: { letterSpacing: "0.05em" }, children: "Relationships" }),
233
- subFeatures.length > 0 && /* @__PURE__ */ jsx(
234
- EdgeGroup,
235
- {
236
- label: `Sub-features (${subFeatures.length})`,
237
- ids: subFeatures,
238
- onNavigateToNode
239
- }
240
- ),
241
- resourcesUsed.length > 0 && /* @__PURE__ */ jsx(
242
- EdgeGroup,
243
- {
244
- label: `Resources used (${resourcesUsed.length})`,
245
- ids: resourcesUsed,
246
- onNavigateToNode
247
- }
248
- ),
249
- entities.length > 0 && /* @__PURE__ */ jsx(EdgeGroup, { label: `Entities (${entities.length})`, ids: entities, onNavigateToNode }),
250
- governedTargets.length > 0 && /* @__PURE__ */ jsx(
251
- EdgeGroup,
252
- {
253
- label: `Governs (${governedTargets.length})`,
254
- ids: governedTargets,
255
- onNavigateToNode
256
- }
257
- ),
258
- governingKnowledge.length > 0 && (knowledgeNodes ? /* @__PURE__ */ jsx(
259
- RelatedKnowledgeSection,
260
- {
261
- nodeId,
262
- graph,
263
- knowledgeNodes,
264
- onNavigateToNode
265
- }
266
- ) : /* @__PURE__ */ jsx(
267
- EdgeGroup,
268
- {
269
- label: `Governing knowledge (${governingKnowledge.length})`,
270
- ids: governingKnowledge,
271
- onNavigateToNode
272
- }
273
- ))
274
- ] });
275
- }
276
- var PRESENTATION_METADATA_KEYS = /* @__PURE__ */ new Set(["label", "description"]);
277
- function formatMetadataLabel(key) {
278
- return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (char) => char.toUpperCase());
279
- }
280
- function NodeMetadataFooter({ node, title = "Technical metadata" }) {
281
- const entries = Object.entries(node).filter(
282
- ([key, value]) => !PRESENTATION_METADATA_KEYS.has(key) && value !== void 0 && value !== null && typeof value !== "object"
283
- );
284
- if (entries.length === 0) return null;
285
- return /* @__PURE__ */ jsxs(
286
- Box,
287
- {
288
- component: "details",
289
- style: {
290
- borderTop: "1px solid var(--color-border)",
291
- paddingTop: "var(--mantine-spacing-sm)"
292
- },
293
- children: [
294
- /* @__PURE__ */ jsx(
295
- Box,
296
- {
297
- component: "summary",
298
- style: {
299
- cursor: "pointer",
300
- color: "var(--color-text-dimmed)",
301
- fontSize: "var(--mantine-font-size-xs)",
302
- fontWeight: 600,
303
- letterSpacing: "0.05em",
304
- textTransform: "uppercase"
305
- },
306
- children: title
307
- }
308
- ),
309
- /* @__PURE__ */ jsx(Stack, { gap: 4, style: { paddingTop: "var(--mantine-spacing-xs)" }, children: entries.map(([key, value]) => /* @__PURE__ */ jsx(KeyField, { label: formatMetadataLabel(key), value: String(value) }, key)) })
310
- ]
311
- }
312
- );
313
- }
314
- function NodeDescribeShell({ header, content, relationships, footer }) {
315
- return /* @__PURE__ */ jsxs(Stack, { gap: "md", style: { padding: "var(--mantine-spacing-md)", width: "100%" }, children: [
316
- header,
317
- content && /* @__PURE__ */ jsxs(Fragment, { children: [
318
- header && /* @__PURE__ */ jsx(Divider, {}),
319
- content
320
- ] }),
321
- relationships,
322
- footer
323
- ] });
324
- }
325
- function KeyField({ label, value }) {
326
- return /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "baseline", children: [
327
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", style: { minWidth: 96 }, children: label }),
328
- /* @__PURE__ */ jsx(Text, { size: "sm", style: { fontFamily: "var(--mantine-font-family-monospace)" }, children: value })
329
- ] });
330
- }
331
- var FEATURE_PREFIX = "feat:";
332
- var LEAF_PREFIX = "leaf:";
333
- var FOLDER_PREFIX = "folder:";
334
- var GROUP_THRESHOLD = 8;
335
- var SIDEBAR_TREE_ACCENT_COLOR = "var(--color-primary)";
336
- var FOLDER_ORDER = [
337
- "campaigns",
338
- "pipeline",
339
- "targeting",
340
- "channels",
341
- "proof",
342
- "references",
343
- "playbooks",
344
- "strategies"
345
- ];
346
- var FOLDER_LABELS = {
347
- campaigns: "Campaigns",
348
- pipeline: "Pipeline",
349
- targeting: "Targeting and Strategy",
350
- channels: "Channels",
351
- proof: "Proof",
352
- references: "References",
353
- playbooks: "Playbooks",
354
- strategies: "Strategies"
355
- };
356
- function toBareFeatureId(graphNodeId) {
357
- return graphNodeId.startsWith("feature:") ? graphNodeId.slice("feature:".length) : graphNodeId;
358
- }
359
- function topLevelFeatureIds(allBareIds) {
360
- return allBareIds.filter((id) => !id.includes("."));
361
- }
362
- function childFeatureIds(allBareIds, parentId) {
363
- const prefix = `${parentId}.`;
364
- return allBareIds.filter((id) => id.startsWith(prefix) && !id.slice(prefix.length).includes("."));
365
- }
366
- function featureHasKnowledgeDescendant(bareId, allBareIds, graph, knowledgeNodes) {
367
- if (byFeature(graph, bareId, knowledgeNodes).length > 0) return true;
368
- return childFeatureIds(allBareIds, bareId).some(
369
- (childId) => featureHasKnowledgeDescendant(childId, allBareIds, graph, knowledgeNodes)
370
- );
371
- }
372
- function buildFeatureMetaMap(graph) {
373
- const map = {};
374
- for (const node of graph.nodes) {
375
- if (node.kind === "feature") {
376
- map[toBareFeatureId(node.id)] = { label: node.label, icon: node.icon, node };
377
- }
378
- }
379
- return map;
380
- }
381
- function getKnowledgeReadCommand(nodeId) {
382
- return `/knowledge read ${nodeId}`;
383
- }
384
- function getKnowledgeReadCommands(nodeIds) {
385
- return [...new Set(nodeIds)].map(getKnowledgeReadCommand).join("\n");
386
- }
387
- function getKnowledgeReadFeatureFolderCommand(bareFeatureId) {
388
- return `/knowledge read-folder feature:${bareFeatureId}`;
389
- }
390
- function getKnowledgeFolderKey(node) {
391
- const key = `${node.id} ${node.title}`.toLowerCase();
392
- if (/\b(stage|booking|discovery|pipeline|communications?)\b/.test(key)) return "pipeline";
393
- if (/\b(upwork scanning|youtube|obs|recording|reddit|social)\b/.test(key)) return "channels";
394
- if (/\b(testimonials?|case stud|proof)\b/.test(key)) return "proof";
395
- if (/\b(target|personalization|vertical|calibration|query|research|strategy)\b/.test(key)) return "targeting";
396
- if (/\b(outreach|campaign|copy|handoff|bounce|reply|lead-gen playbook)\b/.test(key)) return "campaigns";
397
- if (node.kind === "reference") return "references";
398
- if (node.kind === "strategy") return "strategies";
399
- return "playbooks";
400
- }
401
- function sortFolderKeys(left, right) {
402
- const leftIndex = FOLDER_ORDER.indexOf(left);
403
- const rightIndex = FOLDER_ORDER.indexOf(right);
404
- if (leftIndex === -1 && rightIndex === -1) return left.localeCompare(right);
405
- if (leftIndex === -1) return 1;
406
- if (rightIndex === -1) return -1;
407
- return leftIndex - rightIndex;
408
- }
409
- function createKnowledgeLeaf(bareId, node) {
410
- return {
411
- value: `${LEAF_PREFIX}${bareId}::${node.id}`,
412
- label: node.title,
413
- nodeType: "leaf",
414
- knowledgeNodeId: node.id,
415
- knowledgeNodeIds: [node.id]
416
- };
417
- }
418
- function createKnowledgeLeaves(bareId, nodes) {
419
- if (nodes.length < GROUP_THRESHOLD) {
420
- return nodes.map((node) => createKnowledgeLeaf(bareId, node));
421
- }
422
- const grouped = /* @__PURE__ */ new Map();
423
- for (const node of nodes) {
424
- const folderKey = getKnowledgeFolderKey(node);
425
- const folderNodes = grouped.get(folderKey) ?? [];
426
- folderNodes.push(node);
427
- grouped.set(folderKey, folderNodes);
428
- }
429
- return [...grouped.entries()].sort(([left], [right]) => sortFolderKeys(left, right)).map(([folderKey, folderNodes]) => ({
430
- value: `${FOLDER_PREFIX}${bareId}::${folderKey}`,
431
- label: FOLDER_LABELS[folderKey] ?? folderKey,
432
- nodeType: "folder",
433
- icon: "knowledge.playbook",
434
- knowledgeNodeIds: folderNodes.map((node) => node.id),
435
- children: folderNodes.map((node) => createKnowledgeLeaf(bareId, node))
436
- }));
437
- }
438
- function collectKnowledgeNodeIds(node) {
439
- if (node.knowledgeNodeIds) return node.knowledgeNodeIds;
440
- return (node.children ?? []).flatMap(collectKnowledgeNodeIds);
441
- }
442
- function buildFeatureTreeNode(bareId, allBareIds, featureMetaMap, graph, knowledgeNodes) {
443
- const governing = byFeature(graph, bareId, knowledgeNodes);
444
- const childIds = childFeatureIds(allBareIds, bareId);
445
- const childFeatureNodes = childIds.filter((childId) => featureHasKnowledgeDescendant(childId, allBareIds, graph, knowledgeNodes)).map((childId) => buildFeatureTreeNode(childId, allBareIds, featureMetaMap, graph, knowledgeNodes));
446
- const knowledgeLeaves = createKnowledgeLeaves(bareId, governing);
447
- const children = [...childFeatureNodes, ...knowledgeLeaves];
448
- const meta = featureMetaMap[bareId];
449
- return {
450
- value: `${FEATURE_PREFIX}${bareId}`,
451
- label: meta?.label ?? bareId,
452
- nodeType: "feature",
453
- icon: meta?.icon,
454
- knowledgeNodeIds: children.flatMap(collectKnowledgeNodeIds),
455
- children: children.length > 0 ? children : void 0
456
- };
457
- }
458
- function collectExpandableValues(nodes, acc = {}) {
459
- for (const node of nodes) {
460
- if (typeof node.value === "string" && (node.value.startsWith(FEATURE_PREFIX) || node.value.startsWith(FOLDER_PREFIX))) {
461
- acc[node.value] = true;
462
- }
463
- if (node.children) {
464
- collectExpandableValues(node.children, acc);
465
- }
466
- }
467
- return acc;
468
- }
469
- function KnowledgeTree({
470
- graph,
471
- knowledgeNodes,
472
- onSelectNode,
473
- onSelectGraphNode,
474
- selectedNodeId
475
- }) {
476
- const treeData = useMemo(() => {
477
- const featureMetaMap = buildFeatureMetaMap(graph);
478
- const allBareIds = Object.keys(featureMetaMap);
479
- const topIds = topLevelFeatureIds(allBareIds);
480
- return topIds.filter((bareId) => featureHasKnowledgeDescendant(bareId, allBareIds, graph, knowledgeNodes)).map((bareId) => buildFeatureTreeNode(bareId, allBareIds, featureMetaMap, graph, knowledgeNodes));
481
- }, [graph, knowledgeNodes]);
482
- const initialExpandedState = useMemo(() => collectExpandableValues(treeData), [treeData]);
483
- const treeController = useTree({ initialExpandedState });
484
- const leafNodeMap = useMemo(() => {
485
- const map = /* @__PURE__ */ new Map();
486
- for (const node of knowledgeNodes) {
487
- for (const graphNode of graph.nodes) {
488
- if (graphNode.kind === "feature") {
489
- const bareId = toBareFeatureId(graphNode.id);
490
- map.set(`${LEAF_PREFIX}${bareId}::${node.id}`, node);
491
- }
492
- }
493
- }
494
- return map;
495
- }, [graph, knowledgeNodes]);
496
- const featureKnowledgeCountMap = useMemo(() => {
497
- const counts = /* @__PURE__ */ new Map();
498
- for (const graphNode of graph.nodes) {
499
- if (graphNode.kind === "feature") {
500
- const bareId = toBareFeatureId(graphNode.id);
501
- counts.set(bareId, byFeature(graph, bareId, knowledgeNodes).length);
502
- }
503
- }
504
- return counts;
505
- }, [graph, knowledgeNodes]);
506
- const featureGraphNodeMap = useMemo(() => {
507
- const map = /* @__PURE__ */ new Map();
508
- for (const graphNode of graph.nodes) {
509
- if (graphNode.kind === "feature") {
510
- map.set(toBareFeatureId(graphNode.id), graphNode);
511
- }
512
- }
513
- return map;
514
- }, [graph]);
515
- if (treeData.length === 0) {
516
- return /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", style: { padding: "var(--mantine-spacing-md)" }, children: "No features in graph." });
517
- }
518
- return /* @__PURE__ */ jsx(
519
- Tree,
520
- {
521
- data: treeData,
522
- tree: treeController,
523
- style: { padding: "var(--mantine-spacing-xs)" },
524
- renderNode: ({ node, expanded, hasChildren, elementProps }) => {
525
- const value = node.value;
526
- const typedNode = node;
527
- if (typeof value === "string" && value.startsWith(LEAF_PREFIX)) {
528
- const knowledgeNode = leafNodeMap.get(value);
529
- if (!knowledgeNode) return null;
530
- return /* @__PURE__ */ jsx(
531
- KnowledgeLeafRow,
532
- {
533
- elementProps,
534
- knowledgeNode,
535
- isActive: knowledgeNode.id === selectedNodeId,
536
- onSelectNode
537
- }
538
- );
539
- }
540
- if (typeof value === "string" && value.startsWith(FOLDER_PREFIX)) {
541
- return /* @__PURE__ */ jsx(
542
- DirectoryRow,
543
- {
544
- elementProps,
545
- expanded,
546
- hasChildren,
547
- label: String(node.label),
548
- iconToken: typedNode.icon,
549
- count: typedNode.knowledgeNodeIds?.length ?? 0,
550
- command: getKnowledgeReadCommands(typedNode.knowledgeNodeIds ?? []),
551
- isActive: false
552
- }
553
- );
554
- }
555
- const bareId = typeof value === "string" && value.startsWith(FEATURE_PREFIX) ? value.slice(FEATURE_PREFIX.length) : String(value);
556
- const count = featureKnowledgeCountMap.get(bareId) ?? 0;
557
- const graphNode = featureGraphNodeMap.get(bareId);
558
- const isActive = graphNode !== void 0 && (selectedNodeId === graphNode.id || selectedNodeId === graphNode.sourceId || selectedNodeId === bareId);
559
- return /* @__PURE__ */ jsx(
560
- DirectoryRow,
561
- {
562
- elementProps,
563
- expanded,
564
- hasChildren,
565
- label: String(node.label),
566
- iconToken: typedNode.icon,
567
- count,
568
- command: getKnowledgeReadFeatureFolderCommand(bareId),
569
- isActive,
570
- uppercase: true,
571
- onSelectGraphNode: graphNode ? () => onSelectGraphNode?.(graphNode) : void 0
572
- }
573
- );
574
- }
575
- }
576
- );
577
- }
578
- function CopyCommandControl({ command, label, visible }) {
579
- const clipboard = useClipboard({ timeout: 1500 });
580
- if (!command) return null;
581
- return /* @__PURE__ */ jsx(
582
- "span",
583
- {
584
- role: "button",
585
- tabIndex: 0,
586
- "aria-label": label,
587
- onClick: (event) => {
588
- event.preventDefault();
589
- event.stopPropagation();
590
- clipboard.copy(command);
591
- },
592
- onKeyDown: (event) => {
593
- if (event.key !== "Enter" && event.key !== " ") return;
594
- event.preventDefault();
595
- event.stopPropagation();
596
- clipboard.copy(command);
597
- },
598
- style: {
599
- display: "inline-flex",
600
- alignItems: "center",
601
- justifyContent: "center",
602
- width: 22,
603
- height: 22,
604
- flexShrink: 0,
605
- opacity: visible ? 1 : 0,
606
- pointerEvents: visible ? "auto" : "none",
607
- color: clipboard.copied ? "var(--color-primary)" : "var(--color-text-subtle)",
608
- transition: "opacity 120ms ease, color 120ms ease"
609
- },
610
- children: clipboard.copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
611
- }
612
- );
613
- }
614
- function KnowledgeLeafRow({ elementProps, knowledgeNode, isActive, onSelectNode }) {
615
- const [hovered, setHovered] = useState(false);
616
- return /* @__PURE__ */ jsx(
617
- UnstyledButton,
618
- {
619
- ...elementProps,
620
- onMouseEnter: (event) => {
621
- elementProps.onMouseEnter?.(event);
622
- setHovered(true);
623
- },
624
- onMouseLeave: (event) => {
625
- elementProps.onMouseLeave?.(event);
626
- setHovered(false);
627
- },
628
- onClick: () => onSelectNode(knowledgeNode),
629
- style: {
630
- ...elementProps.style ?? {},
631
- padding: "5px 8px 5px 24px",
632
- borderRadius: "var(--mantine-radius-sm)",
633
- backgroundColor: isActive ? "color-mix(in srgb, var(--color-primary) 10%, transparent)" : hovered ? "var(--color-surface-hover)" : "transparent",
634
- width: "100%",
635
- textAlign: "left",
636
- display: "block"
637
- },
638
- children: /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
639
- /* @__PURE__ */ jsx(
640
- SemanticIcon,
641
- {
642
- token: getKnowledgeIconToken(knowledgeNode),
643
- fallbackKind: knowledgeNode.kind,
644
- size: 15,
645
- style: { color: SIDEBAR_TREE_ACCENT_COLOR }
646
- }
647
- ),
648
- /* @__PURE__ */ jsx(
649
- Text,
650
- {
651
- size: "sm",
652
- c: isActive ? "var(--color-primary)" : hovered ? "var(--color-text)" : void 0,
653
- fw: isActive ? 600 : 400,
654
- style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
655
- children: knowledgeNode.title
656
- }
657
- ),
658
- /* @__PURE__ */ jsx(
659
- CopyCommandControl,
660
- {
661
- command: getKnowledgeReadCommand(knowledgeNode.id),
662
- label: "Copy knowledge command",
663
- visible: hovered
664
- }
665
- )
666
- ] })
667
- }
668
- );
669
- }
670
- function DirectoryRow({
671
- elementProps,
672
- expanded,
673
- hasChildren,
674
- label,
675
- iconToken,
676
- count,
677
- command,
678
- isActive,
679
- uppercase = false,
680
- onSelectGraphNode
681
- }) {
682
- const [hovered, setHovered] = useState(false);
683
- return /* @__PURE__ */ jsxs(
684
- Group,
685
- {
686
- ...elementProps,
687
- gap: "xs",
688
- onMouseEnter: (event) => {
689
- elementProps.onMouseEnter?.(event);
690
- setHovered(true);
691
- },
692
- onMouseLeave: (event) => {
693
- elementProps.onMouseLeave?.(event);
694
- setHovered(false);
695
- },
696
- onClick: (event) => {
697
- elementProps.onClick?.(event);
698
- onSelectGraphNode?.();
699
- },
700
- style: {
701
- ...elementProps.style ?? {},
702
- padding: "4px 8px",
703
- borderRadius: "var(--mantine-radius-sm)",
704
- backgroundColor: isActive ? "color-mix(in srgb, var(--color-primary) 10%, transparent)" : hovered ? "var(--color-surface-hover)" : "transparent",
705
- cursor: onSelectGraphNode || hasChildren ? "pointer" : "default",
706
- userSelect: "none"
707
- },
708
- children: [
709
- hasChildren ? /* @__PURE__ */ jsx(
710
- "span",
711
- {
712
- "aria-hidden": "true",
713
- style: {
714
- display: "inline-flex",
715
- alignItems: "center",
716
- justifyContent: "center",
717
- width: 12,
718
- height: 12,
719
- color: SIDEBAR_TREE_ACCENT_COLOR,
720
- flexShrink: 0
721
- },
722
- children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 12, stroke: 2 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 12, stroke: 2 })
723
- }
724
- ) : /* @__PURE__ */ jsx(Text, { size: "xs", style: { width: 12, flexShrink: 0 } }),
725
- /* @__PURE__ */ jsx(
726
- SemanticIcon,
727
- {
728
- token: iconToken,
729
- fallbackKind: "feature",
730
- size: 14,
731
- style: { color: SIDEBAR_TREE_ACCENT_COLOR }
732
- }
733
- ),
734
- /* @__PURE__ */ jsx(
735
- Text,
736
- {
737
- size: "xs",
738
- fw: isActive ? 700 : 600,
739
- tt: uppercase ? "uppercase" : void 0,
740
- c: isActive ? "var(--color-primary)" : hovered ? "var(--color-text)" : void 0,
741
- style: {
742
- letterSpacing: uppercase ? "0.05em" : 0,
743
- flex: 1,
744
- minWidth: 0,
745
- overflow: "hidden",
746
- textOverflow: "ellipsis",
747
- whiteSpace: "nowrap"
748
- },
749
- children: label
750
- }
751
- ),
752
- /* @__PURE__ */ jsx(TrailingCopySlot, { count, command, label: "Copy folder knowledge commands", showCopy: hovered })
753
- ]
754
- }
755
- );
756
- }
757
- function TrailingCopySlot({ count, command, label, showCopy }) {
758
- return /* @__PURE__ */ jsx(
759
- "span",
760
- {
761
- style: {
762
- display: "inline-flex",
763
- alignItems: "center",
764
- justifyContent: "center",
765
- width: 32,
766
- height: 22,
767
- flexShrink: 0
768
- },
769
- children: showCopy && command ? /* @__PURE__ */ jsx(CopyCommandControl, { command, label, visible: true }) : count > 0 ? /* @__PURE__ */ jsx(KindChip, { kind: String(count), tone: "primary" }) : null
770
- }
771
- );
772
- }
1
+ import './chunk-I2KLQ2HA.js';
773
2
 
774
3
  // src/knowledge/_generated/knowledge-search-index.json
775
4
  var knowledge_search_index_default = [
@@ -788,8 +17,8 @@ var knowledge_search_index_default = [
788
17
  {
789
18
  id: "knowledge.org-model-reference",
790
19
  title: "Organization Model Schema Reference",
791
- summary: "Technical reference for the OrganizationModel Zod schema: all domains, field contracts, and versioning rules.",
792
- bodyText: "Schema\n\nThe OrganizationModel schema is defined in packages/core/src/organization-model/schema.ts. It is versioned at version: 1 and composed from domain sub-schemas.\n\nDomains\n\n- features \u2014 flat array of FeatureSchema nodes (nav tree)\n- knowledge \u2014 flat array of KnowledgeNodeSchema nodes\n- sales, prospecting, projects \u2014 sales and GTM domains\n- operations, statuses \u2014 runtime entity domains\n- customers, offerings, roles, goals \u2014 business context domains"
20
+ summary: "Technical reference for the OrganizationModel Zod schema: all top-level domains, the graph contract orientation, authored primitives versus projected graph nodes, and versioning rules.",
21
+ bodyText: "Schema\n\nThe OrganizationModel schema is defined in packages/core/src/organization-model/schema.ts. It is versioned at version: 1 and composed from domain sub-schemas. The OM is the authoritative contract for the organization: downstream surfaces including Command View, the Knowledge Browser, and the navigation shell are all derived projections from this schema.\n\nTop-Level Domains\n\nThese are the current top-level fields on OrganizationModel. There is no live features or capabilities top-level field -- those terms are legacy wording and should not appear as authored OM primitives.\n\n- version -- schema version, currently locked at 1\n- domainMetadata -- per-domain version and lastModified tracking\n- branding -- organization name, logo, color identity\n- navigation -- surfaces, groups, and defaultSurfaceId for shell routing\n- sales -- sales domain including pipeline entity references\n- prospecting -- lead generation stages, entity references, and pipeline config\n- projects -- project, milestone, and task entity references\n- identity -- organization identity fields\n- customers -- customer segment definitions\n- offerings -- product and service definitions linked to customer segments\n- roles -- role definitions with reportsToId hierarchy and agentId holder support\n- goals -- OKR-style objectives with period ranges and system links\n- systems -- the backbone: hierarchical bounded contexts with dotted IDs and parentSystemId\n- resources -- governance descriptors for workflows, agents, integrations, triggers, and scripts; resource identity lives here, not in a separate deployment manifest\n- actions -- the invokable semantic layer; actions map to resources, affect entities, bind to knowledge, and expose invocation types (slash command, MCP tool, API endpoint, script execution)\n- entities -- business objects owned by systems, with table metadata, state catalogs, and typed entity links\n- policies -- governance rules applied to systems, actions, resources, and roles\n- statuses -- runtime semantic status registry\n- knowledge -- first-class OM content backed by inline nodes and MDX source nodes\n\nGraph Contract\n\nThe OM is projected into a typed graph by buildOrganizationGraph() in packages/core/src/organization-model/graph/build.ts.\n\nNode kinds: organization, system, role, action, entity, event, policy, stage, resource, knowledge\n\nEdge kinds: contains, references, mapsto, uses, governs, links, affects, emits, originatesfrom, triggers, appliesto, effects\n\nThe resourceType overlay on resource nodes is a separate enum: workflow, agent, trigger, integration, external, humancheckpoint, script.\n\nAuthored Primitives vs Projected Graph Nodes\n\nAuthored primitives are what you write directly in the OM: systems, roles, resources, actions, entities, policies, knowledge. The graph builder reads these and emits a richer set of typed nodes and edges. Events, for example, are not authored directly -- they are projected from resource emits declarations. Stages are projected from prospecting stage catalogs.\n\nCommand View\n\nCommand View is a derived operational projection of the OM graph. It visualizes systems, resources, actions, entities, and relationships using the same node and edge taxonomy as buildOrganizationGraph(). It does not have a separate deployment manifest model -- the OM resources domain is the single source of resource identity."
793
22
  },
794
23
  {
795
24
  id: "knowledge.seo-lead-gen-playbook",
@@ -1375,9 +604,9 @@ Each stage desensitizes one fear at a time. Never skip ahead. The goal is consis
1375
604
  bodyText: 'Executive Summary\n\nCompany: Bootstrapped AI orchestration platform for done-for-you business automation\n\nFounder: Solo (Alex, 34), bootstrapped\n\nMarket: Service-based SMBs that need practical AI automation without building internal AI teams\n\nGTM: Content-led marketing, proof assets, consultative sales, and land-and-expand pricing\n\nCompany Overview\n\nCurrent Status\n\nThe platform core is production-ready enough to support client-facing demonstrations and implementation work. Current business focus is client acquisition, proof-building, and turning the platform into a repeatable service delivery system.\n\nFounder Profile\n\nAlex, 34 \u2014 Solo founder with software engineering background (BSCS degree). Previous: Ecommerce platforms, Streaming technology. No formal AI background \u2014 practitioner, not academic.\n\nWhat We Are\n\nOperating layer for AI automation. We help SMBs operate with closed-loop feedback, decision capture, and continuous learning \u2014 at SMB pricing with done-for-you implementation (NOT self-service).\n\nTarget Market\n\nICP: Service-based SMBs (2-50 employees, USA, $200K-$5M revenue)\n\nCore Pain: Capacity crisis, pipeline problems, operational chaos, growth blockers \u2014 too busy serving clients to grow their own business.\n\nPricing (Land-and-Expand)\n\n- Tier 1 \u2014 Foundation (1-2 workflows): $500-2k/mo\n- Tier 2 \u2014 Scaled Operations (3-5 workflows): $2k-5k/mo\n- Tier 3 \u2014 AI-Powered Systems (6+ workflows): $5k-15k+/mo\n\nAdditional workflows cost less due to shared infrastructure.\n\nValue Proposition\n\n"We find one bottleneck in your business, build an AI solution to fix it, and you only pay if it actually saves you time or makes you money."'
1376
605
  },
1377
606
  {
1378
- id: "knowledge.platform-capabilities",
1379
- title: "Platform Capabilities",
1380
- summary: "Authoritative overview of the Elevasis AI Orchestration Platform \u2014 what's built, what it does, and how the pieces fit together",
607
+ id: "knowledge.platform-systems-overview",
608
+ title: "Platform Systems Overview",
609
+ summary: "Authoritative overview of the Elevasis AI Orchestration Platform systems -- what's built, what each system does, and how the pieces fit together",
1381
610
  bodyText: "Overview\n\nElevasis is a production AI orchestration platform that coordinates workflows, autonomous agents, and human approvals into a unified operating layer for SMBs. Everything described below is implemented and running in production.\n\nCore Architecture:\n\n| Layer | What It Does | Key Components |\n| --- | --- | --- |\n| Execution | Runs workflows and agents with schema validation | Workflow Engine, Agent Framework, Execution Runner |\n| Control | Human oversight, approvals, and decision capture | Command Queue (HITL), Dynamic Forms, Action System |\n| Intelligence | Autonomous reasoning, tool use, and memory management | ReAct Agents, Knowledge Map, Session Memory |\n| Observability | Real-time visibility into cost, performance, and health | Cost Tracking, Metrics, Activity Log, SSE Streaming |\n| Platform | Multi-tenancy, security, scheduling, integrations | Registry, RLS, Scheduler, Credential Vault, SDK |\n\nExecution Engine\n\nAI Workflows\n\nGraph-based workflow execution with schema-validated steps and conditional routing. Steps define explicit routing: linear, conditional (rule-based branching), or terminal. Context flows through the entire workflow.\n\nAutonomous Agents\n\nProduction-grade ReAct-style agents with tool use, memory management, and security hardening.\n\nLLM Provider Support: OpenAI (GPT-5), Google (Gemini 3 Flash), Anthropic (Claude Sonnet 4.5), OpenRouter (GLM-5)\n\nHuman-in-the-Loop (HITL)\n\nThe Command Queue surfaces pending approvals as structured tasks. Admin reviews, approves or edits, and the workflow continues. Every critical decision \u2014 sending emails to prospects, updating customer records, publishing content \u2014 requires human approval.\n\nKnowledge Map\n\nOrganizational knowledge loaded lazily into agent context. 80-95% token savings vs. always-loading full context. Nodes link to features, teams, and other nodes.\n\nIntegrations (13 active)\n\nAttio CRM, Cal.com, Instantly (cold email), Resend, Apify, Google Maps, Tomba, Mails.so, Supabase, Stripe, OpenAI, Google Gemini, Anthropic Claude.\n\nSDK\n\nTypeScript-based resource development with local testing, validation, and deployment pipeline. External consumers define workflows and agents in their own repos and deploy via elevasis-sdk deploy."
1382
611
  },
1383
612
  {
@@ -1428,8 +657,8 @@ Permission: Case study approved with company name.`
1428
657
  {
1429
658
  id: "knowledge.understanding-elevasis",
1430
659
  title: "Understanding Elevasis Overview",
1431
- summary: "Company overview, product positioning, and platform capability context for Elevasis AI orchestration platform",
1432
- bodyText: "Lean documentation explaining what Elevasis is and what the platform can do. This section provides the foundational context for business conversations and technical evaluation.\n\nElevasis is a done-for-you AI automation service backed by a production-grade platform. The company targets service-based SMBs (2-50 employees, $200K-$5M revenue) who are too busy serving clients to grow their own business.\n\nKey Facts\n\n- Stage: Pre-revenue, platform 100% complete, client acquisition active\n- Offer: Done-for-you AI automation -- we build and maintain the workflows, no coding required\n- ICP: Service-based SMBs (2-50 employees, $200K-$5M revenue, USA)\n- Pricing: $500-$2k/mo (Foundation) \u2192 $2k-$5k/mo (Scaled) \u2192 $5k-$15k+/mo (AI-Powered)\n- Market: Early Adopters stage, $23.77B TAM growing to $87.7B by 2032\n- Competitive position: No dominant done-for-you SMB AI provider exists; blue ocean\n\nWhen to Use Each Document\n\n| Situation | Document |\n| --- | --- |\n| First conversation with any audience | What is Elevasis |\n| Technical evaluation or demo prep | Platform Capabilities |\n\nDocumentation\n\n- What is Elevasis \u2014 AI orchestration platform overview, company stage, value proposition, and pricing tiers\n- Platform Capabilities \u2014 Authoritative overview of what is built, what it does, and how the pieces fit together"
660
+ summary: "Company overview, product positioning, and platform systems context for Elevasis AI orchestration platform",
661
+ bodyText: "Lean documentation explaining what Elevasis is and what the platform can do. This section provides the foundational context for business conversations and technical evaluation.\n\nElevasis is a done-for-you AI automation service backed by a production-grade platform. The company targets service-based SMBs (2-50 employees, $200K-$5M revenue) who are too busy serving clients to grow their own business.\n\nKey Facts\n\n- Stage: Pre-revenue, platform 100% complete, client acquisition active\n- Offer: Done-for-you AI automation -- we build and maintain the workflows, no coding required\n- ICP: Service-based SMBs (2-50 employees, $200K-$5M revenue, USA)\n- Pricing: $500-$2k/mo (Foundation) \u2192 $2k-$5k/mo (Scaled) \u2192 $5k-$15k+/mo (AI-Powered)\n- Market: Early Adopters stage, $23.77B TAM growing to $87.7B by 2032\n- Competitive position: No dominant done-for-you SMB AI provider exists; blue ocean\n\nWhen to Use Each Document\n\n| Situation | Document |\n| --- | --- |\n| First conversation with any audience | What is Elevasis |\n| Technical evaluation or demo prep | Platform Systems Overview |\n\nDocumentation\n\n- What is Elevasis \u2014 AI orchestration platform overview, company stage, value proposition, and pricing tiers\n- Platform Systems Overview \u2014 Authoritative overview of what is built, what each system does, and how the pieces fit together"
1433
662
  },
1434
663
  {
1435
664
  id: "knowledge.marketing-overview",
@@ -2144,11 +1373,94 @@ Pre-Recording Checklist
2144
1373
  summary: "Operating playbook for Elevasis finance: Xero as the system of record, Stripe payment collection and payout reconciliation, invoicing and AR cadence, tax estimates, deductions, 1099s, and annual filing prep.",
2145
1374
  bodyText: "Overview\n\nElevasis finance operations run through Xero, with Stripe handling payment collection. Xero is the single source of truth for financial records: business checking bank feeds, Stripe payouts, contractor payments, expenses, invoices, receivables, and year-end exports.\n\nThe finance loop has three connected parts:\n\n1. Invoicing captures client revenue through monthly retainers and Stripe Checkout.\n2. Accounting records and reconciles bank transactions, Stripe payouts, contractor payments, and operating expenses.\n3. Taxes use accurate Xero records for quarterly estimates, deductions, 1099s, and annual filing.\n\nAccounting and Reconciliation\n\nReconcile bank transactions in Xero weekly. Match each bank feed entry to its real-world source before month end.\n\n- Stripe payouts should match against Stripe bank feed activity.\n- Contractor payments should match checking account transfers.\n- Software subscriptions such as Railway, Vercel, Supabase, WorkOS, and OpenAI should be categorized as operating expenses.\n- Unmatched or ambiguous transactions should be flagged for manual review before monthly close.\n\nMaintain the core chart of accounts around revenue, cost of sales, operating expenses, and owner draws. Revenue includes client retainers and one-time project fees. Cost of sales covers contractor labor directly tied to client work. Operating expenses cover SaaS tools, hosting, banking fees, and professional services. Owner draws track business distributions.\n\nConfigure Xero with the connected business checking account, the default tax rate for the business jurisdiction, and the correct financial year end in organization settings.\n\nInvoicing and Accounts Receivable\n\nClient billing runs on a monthly retainer model. Create invoices in Xero at the start of each billing period, send them by Xero email or Stripe Checkout link, record payment after Stripe confirms checkout completion, and reconcile the Stripe payout in Xero.\n\nUse Xero repeating invoices for monthly retainers:\n\n- Frequency: monthly.\n- Start date: billing cycle start date.\n- Approval: automatic approval where the billing terms are stable.\n\nConfigure invoice reminders around the due date: a courtesy reminder 3 days before due date, an overdue notice 1 day after due date, and an escalation notice 7 days after due date.\n\nFor invoices more than 14 days overdue, contact the client directly through the active communication channel, pause active work pending payment confirmation, and resolve the balance before the next billing cycle.\n\nTaxes\n\nTax work depends on accurate Xero records throughout the year. As a pass-through entity, Elevasis business income flows to the owner personal return, so quarterly estimates reduce underpayment risk and year-end exports should be clean enough for a CPA or tax preparer.\n\nQuarterly estimated payment targets:\n\n- Q1: April 15.\n- Q2: June 15.\n- Q3: September 15.\n- Q4: January 15 of the following year.\n\nEstimate payments as roughly 25-30% of net profit for the quarter and pay via IRS Direct Pay or EFTPS.\n\nTrack deductible expenses in Xero during the year: SaaS subscriptions, contractor payments, home office expenses where applicable, professional development, courses, and business banking fees. Keep digital receipts organized by year in the business records folder.\n\nIssue 1099-NEC forms to US-based contractors paid more than $600 in a calendar year. Collect a W-9 before first payment, track annual contractor totals in Xero, file 1099-NEC forms by January 31 of the following year, and file the 1096 summary with the IRS when required.\n\nAt year end, export the Xero profit and loss statement and balance sheet. Provide them to the CPA or tax preparer with issued 1099s, bank statements for the business year, mileage logs if applicable, and home office documentation if applicable."
2146
1375
  },
1376
+ {
1377
+ id: "knowledge.org-model-actions",
1378
+ title: "Organization Model Actions",
1379
+ summary: "Actions are the invokable semantic layer of the Organization Model -- they map to resources, affect entities, bind to knowledge, and expose four invocation types.",
1380
+ bodyText: `Overview
1381
+
1382
+ Actions are the invokable semantic layer of the Organization Model. They declare what an organization can do: what resources implement them, which entities they affect, and how they can be called.
1383
+
1384
+ Actions are authored in the OM.actions domain map and projected as action graph nodes by buildOrganizationGraph(). Each action emits a contains edge from the organization root and optional mapsto, affects, and triggers edges based on its declared fields.
1385
+
1386
+ Source schema: packages/core/src/organization-model/domains/actions.ts
1387
+
1388
+ What Actions Are
1389
+
1390
+ An action is a named, typed, invokable operation. It is not executable code -- it is a semantic declaration that says "this operation exists, it can be called this way, it affects these business objects, and it is implemented by this resource."
1391
+
1392
+ Actions answer questions like:
1393
+
1394
+ - What operations does the sales.lead-gen system expose?
1395
+ - Which workflow implements the lead-gen.company.qualify operation?
1396
+ - What entities does this action modify?
1397
+ - How can this action be invoked from the CLI, an API, or an MCP client?
1398
+
1399
+ ActionInvocation Kinds
1400
+
1401
+ Each action can declare one or more invocations. An invocation describes how the action is called.
1402
+
1403
+ | Kind | Fields | Description |
1404
+ | ------------------ | ---------------------------------------------------------- | ----------------------------------------- |
1405
+ | slash-command | command (must start with /), optional toolFactory | Called from the CLI or agent tool surface |
1406
+ | mcp-tool | server, name | Exposed as an MCP tool on a named server |
1407
+ | api-endpoint | method (GET/POST/PATCH/DELETE), path, optional schemas | Called via HTTP API endpoint |
1408
+ | script-execution | resourceId | Executed by running a script resource |
1409
+
1410
+ Multiple invocations on one action mean the same semantic operation is reachable through multiple surfaces.
1411
+
1412
+ Scope
1413
+
1414
+ Actions are either global or domain-scoped.
1415
+
1416
+ - Global (scope: 'global'): available across all systems.
1417
+ - Domain-scoped (scope: { domain: '<modelId>' }): associated with a specific OM domain such as sales.
1418
+
1419
+ Systems reference actions through ActionRef entries on system.actions[], with an intent of exposes (the system owns the action) or consumes (the system calls the action). This relationship emits a uses edge from the system to the action in the graph.
1420
+
1421
+ Affects and Knowledge Bindings
1422
+
1423
+ Actions can declare which entities they modify via the affects field (array of entity IDs). Each entry emits an affects edge from the action to the entity node.
1424
+
1425
+ Actions can also declare knowledge bindings (array of knowledge node IDs) that reference relevant reference material. These bindings are not graph edges; they associate documentation with the action for surfacing in the Knowledge Base.
1426
+
1427
+ Resource Mapping
1428
+
1429
+ The optional resourceId field links an action to its implementation resource. Setting resourceId emits a mapsto edge from the action node to the resource node. If the resource does not yet exist in OM.resources, the graph builder creates a stub resource node from the ID.
1430
+
1431
+ Lifecycle States
1432
+
1433
+ Actions follow a five-stage lifecycle: draft, beta, active, deprecated, archived. The default is active. Lifecycle state is authored on the action entry and is reflected in the graph node.`
1434
+ },
1435
+ {
1436
+ id: "knowledge.org-model-entities",
1437
+ title: "Organization Model Entities",
1438
+ summary: "Entities model business objects owned by systems -- with table metadata, state catalogs, and typed entity links.",
1439
+ bodyText: "Overview\n\nEntities are the business objects of the Organization Model. Each entity is a named, typed object owned by a system -- it corresponds to a database table, optionally participates in a state catalog, and can declare typed relationships to other entities.\n\nEntities are authored in the OM.entities domain map and projected as entity graph nodes by buildOrganizationGraph(). Each entity emits a contains edge from its owning system node and optional links edges to related entities.\n\nSource schema: packages/core/src/organization-model/domains/entities.ts\n\nWhat Entities Are\n\nAn entity declaration answers questions like:\n\n- What business objects does the sales.crm system own?\n- Which database table backs the crm.deal entity?\n- What states can a leadgen.company pass through?\n- How are crm.deal and crm.contact related?\n\nEntities are not executable. They are semantic declarations that describe the shape of business data: who owns it, where it lives, what states it can be in, and how it connects to other objects.\n\nownedBySystemId\n\nEvery entity must declare ownedBySystemId -- the ID of the system responsible for it. The graph builder emits a contains edge from system:<ownedBySystemId> to the entity node. An entity can only be owned by one system.\n\nTable and Row Schema\n\nThe optional table field names the backing database table (e.g. crmdeals). The optional rowSchema field references a schema identifier that describes the row shape. These fields are informational references; they are not validated against the database at OM parse time.\n\nstateCatalogId\n\nThe optional stateCatalogId field links the entity to a state catalog. The graph builder uses this to project event nodes for each state transition:\n\n- For general status catalogs, the builder walks OM.statuses entries whose semanticClass matches the catalog ID.\n- For crm.pipeline, the builder also walks pipeline stages from OM.sales.\n- For delivery.task, the builder walks task statuses from OM.projects.\n- For lead-gen.company and lead-gen.contact, the builder walks the lead-gen stage catalog.\n\nEach matching status or stage generates an event node with an originatesfrom edge pointing back to the entity.\n\nTyped Entity Links\n\nThe links field declares typed relationships to other entities. Each link has:\n\n- toEntity -- the target entity ID.\n- kind -- one of belongs-to, has-many, has-one, or many-to-many.\n- via -- optional join key or junction table name.\n- label -- optional display label for the relationship.\n\nEach link emits a links edge from the entity node to the target entity node in the graph.\n\nExample Entity Shape\n\nA crm.deal entity owned by sales.crm, backed by the crmdeals table, in the crm.pipeline state catalog, with a has-many link to crm.contact via the dealcontacts junction:\n\n- id: crm.deal\n- ownedBySystemId: sales.crm\n- table: crmdeals\n- stateCatalogId: crm.pipeline\n- links: [{ toEntity: 'crm.contact', kind: 'has-many', via: 'dealcontacts' }]"
1440
+ },
1441
+ {
1442
+ id: "knowledge.org-model-events",
1443
+ title: "Organization Model Events",
1444
+ summary: "Events are projected signals -- the OM has no authored event domain. They emit from resources and originate from entity state catalogs.",
1445
+ bodyText: "Overview\n\nEvents are projected graph nodes. The Organization Model has no OM.events domain map that authors edit directly. Instead, events are derived by buildOrganizationGraph() from two sources: EventEmissionDescriptor entries on workflow and agent resources, and state catalog entries on entities.\n\nEvery event node carries a unique ID formed as \\<ownerId\\>:\\<eventKey\\>, a human-readable label, and an edge that connects it back to the node that produced it.\n\nProjection logic: packages/core/src/organization-model/graph/build.ts\n\nAuthored vs. Projected\n\nThe distinction matters because it determines where you change event data.\n\nEvents are never edited in a standalone events file. To change an event you must change its source:\n\n- To change a resource-emitted event, update the emits array on the workflow or agent entry in OM.resources.\n- To change an entity state-transition event, update the entity's stateCatalogId or the underlying status/stage entry in the relevant catalog domain.\n\nThe graph builder projects these into event graph nodes automatically on the next call to buildOrganizationGraph().\n\nEventEmissionDescriptor on Resources\n\nWorkflow and agent resource entries can declare an emits array. Each element is an EventEmissionDescriptor:\n\n| Field | Type | Description |\n| --------------- | --------------- | ------------------------------------------------------------- |\n| eventKey | ModelIdSchema | Short key scoped to the owner resource (e.g. enrolled) |\n| label | string | Human-readable label for the event |\n| payloadSchema | ModelIdSchema | Optional reference to a schema that describes the payload |\n| lifecycle | lifecycle enum | Optional: draft, beta, active, deprecated, archived |\n\nThe graph builder constructs the full EventDescriptor by combining ownerId (the resource ID), ownerKind: 'resource', and the emission descriptor fields. The resulting event ID is \\<resourceId\\>:\\<eventKey\\>.\n\nAn emits edge is then projected from the resource node to the event node.\n\nOnly workflow and agent resource kinds support emits. integration and script resources do not.\n\noriginatesfrom Edges from Entity State Catalogs\n\nWhen an entity declares a stateCatalogId, the graph builder projects one event node per state transition available to that entity. These events use ownerKind: 'entity' and the resulting event ID is \\<entityId\\>:\\<eventKey\\>.\n\nA reversed originatesfrom edge is projected from the event node pointing back to the entity node. This edge direction is the opposite of emits: it signals that the event represents a state change that originates from the entity, not that the entity actively fires the event.\n\nThe builder resolves state catalogs as follows:\n\n- General status catalogs: walks OM.statuses entries whose semanticClass matches the entity's stateCatalogId.\n- crm.pipeline: also walks pipeline stages from OM.sales that reference the entity.\n- delivery.task: also walks task statuses from OM.projects.\n- lead-gen.company and lead-gen.contact: walks the LEADGENSTAGECATALOG constant, filtering by entity type.\n\ntriggers Edges to Policies\n\nWhen a policy declares trigger.kind: 'event', the graph builder looks up the projected event node by event ID and emits a triggers edge from the event node to the policy node. This edge is only emitted if the event node was already projected by the time the policy loop runs.\n\nPolicy triggers are the primary way events connect to downstream behavior. No triggers edge is emitted for events that no policy references.\n\nEventDescriptor Full Shape\n\nEventDescriptor is the resolved type used internally by the graph builder. It extends EventEmissionDescriptor with identity fields:\n\n| Field | Type | Description |\n| --------------- | -------------------------- | ----------------------------------------------------- |\n| id | EventIdSchema | Composite: \\<ownerId\\>:\\<eventKey\\> |\n| ownerId | resource ID or model ID | ID of the resource or entity that is the event source |\n| ownerKind | 'resource' or 'entity' | Discriminates between the two projection paths |\n| eventKey | ModelIdSchema | Short key, unique within the owner |\n| label | string | Human-readable label |\n| payloadSchema | ModelIdSchema (opt) | Schema reference for payload shape |\n| lifecycle | lifecycle enum (opt) | Lifecycle state from the emission descriptor |\n\nEventDescriptor is not stored in the graph node itself -- it is used transiently during graph construction to build the node and emit edges. The graph node stores id, kind: 'event', label, and sourceId.\n\nGraph Summary\n\n| Edge kind | Direction | When emitted |\n| ----------------- | --------------------------- | -------------------------------------------- |\n| emits | resource node -> event node | Resource emits[] array is non-empty |\n| originatesfrom | event node -> entity node | Entity has a stateCatalogId |\n| triggers | event node -> policy node | Policy trigger.kind === 'event' matches ID |"
1446
+ },
1447
+ {
1448
+ id: "knowledge.org-model-graph-contract",
1449
+ title: "Organization Model Graph Contract",
1450
+ summary: "The canonical graph node and edge contract -- 10 node kinds, 12 edge kinds, and the resource-type overlay derived from the Organization Model.",
1451
+ bodyText: "Overview\n\nThe Organization Model graph contract defines the typed node and edge taxonomy emitted by buildOrganizationGraph(). Every surface that reads or visualizes the OM -- including Command View -- works against this contract.\n\nThe graph has two categories of nodes: authored nodes derived directly from OM domain maps, and projected nodes derived by the graph builder from authored content. Events and stages are projected; all other node kinds are authored.\n\nSource schema: packages/core/src/organization-model/graph/schema.ts\nProjection logic: packages/core/src/organization-model/graph/build.ts\n\nNode Kinds\n\nTen node kinds are valid in the graph.\n\n| Kind | Authored / Projected | Source |\n| -------------- | -------------------- | ------------------------------------------------------- |\n| organization | Projected | Root node; always present; id is organization-model |\n| system | Authored | OM.systems domain map |\n| role | Authored | OM.roles domain map |\n| action | Authored | OM.actions domain map |\n| entity | Authored | OM.entities domain map |\n| event | Projected | Derived from resource emits and entity state catalogs |\n| policy | Authored | OM.policies domain map |\n| stage | Projected | Derived from OM.prospecting stage catalogs |\n| resource | Authored | OM.resources domain map |\n| knowledge | Authored | OM.knowledge.nodes array |\n\nEdge Kinds\n\nTwelve edge kinds are valid in the graph.\n\n| Kind | Direction | Meaning |\n| ----------------- | ------------------------------------- | ------------------------------------------------------------- |\n| contains | parent -> child | Containment: organization to system, system to resource, etc. |\n| references | source -> target | Cross-reference: role reports-to, agent invokes action |\n| mapsto | action -> resource | Action is implemented by a resource |\n| uses | system -> action, stage -> action | System or stage uses an action |\n| governs | knowledge -> target, role -> system | Knowledge node or role governs a target |\n| links | entity -> entity | Typed entity relationship (belongs-to, has-many, etc.) |\n| affects | action -> entity | Action modifies or reads an entity |\n| emits | resource -> event | Resource produces an observable event |\n| originatesfrom | event -> entity | Event originates from an entity state transition |\n| triggers | event -> policy, action -> policy | Event or action invocation triggers a policy evaluation |\n| appliesto | policy -> system/action/resource/role | Policy governs the target |\n| effects | policy -> action/role | Policy effect invokes an action or notifies a role |\n\nResource Type Overlay\n\nResource nodes carry an optional resourceType field that is a separate enum from kind. It is set by the graph builder from the OM resource kind field or from Command View data.\n\n| Value | Description |\n| ------------------ | --------------------------------- |\n| workflow | Deterministic automation pipeline |\n| agent | LLM-driven reasoning resource |\n| trigger | Event-driven entry point |\n| integration | External service connector |\n| external | Third-party system reference |\n| humancheckpoint | Human-in-the-loop review gate |\n| script | One-shot executable script |\n\nAuthored vs. Projected Fields\n\nAuthored nodes\n\nSystem, role, action, entity, policy, resource, and knowledge nodes are authored in the OM domain maps. Their id, label, description, and domain-specific fields are set from OM source data.\n\nProjected nodes\n\n- Organization node: always present; id is always organization-model.\n- Event nodes: derived from two sources. Resource events come from resource.emits declarations on workflow and agent resources. Entity events come from the entity's stateCatalogId -- the builder walks the matching statuses and pipeline/project stage catalogs to generate one event node per transition.\n- Stage nodes: derived from OM.prospecting.companyStages and OM.prospecting.contactStages.\n\nProjected nodes are never authored directly. To add an event, declare emits on a resource or assign stateCatalogId to an entity.\n\nGraph Node Shape\n\nEach node has: id (graph-unique string), kind (one of the 10 kinds), label (display name), optional sourceId (OM domain ID), optional description, optional icon, optional enabled flag, and optional resourceType (resource nodes only).\n\nEach edge has: id (graph-unique string), kind (one of the 12 kinds), sourceId, targetId, optional label, and optional relationshipType (triggers, uses, or approval)."
1452
+ },
1453
+ {
1454
+ id: "knowledge.org-model-policies",
1455
+ title: "Organization Model Policies",
1456
+ summary: "Policies govern systems, actions, resources, and roles -- with discriminated triggers, predicates, and effects.",
1457
+ bodyText: "Overview\n\nPolicies are cross-cutting governance rules in the Organization Model. They declare what should happen when a trigger fires, under what conditions, and with what effect. Policies are authored in the OM.policies domain map and projected as policy graph nodes by buildOrganizationGraph().\n\nEvery policy emits a contains edge from the organization root and appliesto edges to each system, action, resource, or role it governs. When the trigger is event-based or action-based, an additional triggers edge connects the source node to the policy.\n\nSource schema: packages/core/src/organization-model/domains/policies.ts\n\nPolicyTrigger\n\nThe trigger is a discriminated union on kind that defines what activates the policy.\n\n| Kind | Required fields | Description |\n| ------------------- | --------------- | --------------------------------------------------------- |\n| event | eventId | Fires when the referenced event is projected in the graph |\n| action-invocation | actionId | Fires when the referenced action is invoked |\n| schedule | cron | Fires on a cron schedule (max 120 chars) |\n| manual | none | Fires only when explicitly triggered by a user or process |\n\nFor event triggers, the graph builder looks up the projected event node by eventId and emits a triggers edge from that event node to the policy node. For action-invocation triggers, a triggers edge is emitted from the action node to the policy node. Schedule and manual triggers produce no additional graph edges.\n\nPolicyPredicate\n\nThe predicate is a discriminated union on kind that defines the condition under which the policy effect is applied.\n\n| Kind | Required fields | Description |\n| ------------ | ------------------------------- | ---------------------------------------------------------- |\n| always | none | Condition is unconditionally true; effect always fires |\n| expression | expression (string, max 2000) | Arbitrary expression evaluated at runtime |\n| threshold | metric, operator, value | Numeric threshold check: lt, lte, eq, gte, or gt |\n\nThe default predicate if not specified is { kind: 'always' }.\n\nPolicyEffect\n\nThe actions field holds an ordered array of effects (PolicyEffect[]). At least one effect is required. Effects are a discriminated union on kind.\n\n| Kind | Required fields | Description |\n| ------------------ | ------------------- | ----------------------------------------------------------- |\n| require-approval | roleId (optional) | Blocks execution until a human approves; routes to the role |\n| invoke-action | actionId | Invokes the referenced action as a consequence |\n| notify-role | roleId | Sends a notification to the specified role |\n| block | none | Stops execution entirely; no approval path |\n\nFor invoke-action effects, the graph builder emits an effects edge from the policy node to the referenced action node. For notify-role and require-approval effects that include a roleId, an effects edge is emitted from the policy node to the role node.\n\nappliesTo\n\nThe appliesTo field declares which OM entities the policy governs. It contains four ID arrays, all defaulting to empty:\n\n| Field | Target kind | Graph edge emitted |\n| ------------- | ----------- | ----------------------------------------- |\n| systemIds | system | appliesto from policy to system node |\n| actionIds | action | appliesto from policy to action node |\n| resourceIds | resource | appliesto from policy to resource node |\n| roleIds | role | appliesto from policy to role node |\n\nA policy can apply to any combination of these targets simultaneously. A policy with all four arrays empty is valid but produces no appliesto edges.\n\nLifecycle\n\nPolicies follow the same five-stage lifecycle as systems and actions: draft, beta, active, deprecated, archived. The default is active. Lifecycle is authored on the policy entry and is reflected in the graph node.\n\nThe order field controls domain-map iteration order. The convention is multiples of 10 (10, 20, 30, ...) to allow easy insertion between existing entries.\n\nGraph Summary\n\n| Edge kind | Direction | When emitted |\n| ------------ | ------------------------------------------ | ---------------------------------------------------------------------------------- |\n| contains | organization root -> policy node | Always; every policy is contained by the organization root |\n| appliesto | policy node -> system/action/resource/role | For each non-empty appliesTo.Ids entry |\n| triggers | event or action node -> policy node | When trigger.kind is event or action-invocation |\n| effects | policy node -> action or role node | For invoke-action, notify-role, and require-approval effects with a roleId |"
1458
+ },
2147
1459
  {
2148
1460
  id: "knowledge.platform-command-view",
2149
1461
  title: "Platform Command View",
2150
- summary: "Reference for Command View, the read-only graph surface for organization automation resources, relationships, manifest validation, graph modes, filters, and troubleshooting.",
2151
- bodyText: "Overview\n\nCommand View visualizes an organization's automation landscape: agents, workflows, triggers, integrations, external resources, and human checkpoints, plus the relationships between them.\n\nIt answers operational questions such as:\n\n- What does this agent talk to?\n- If a provider goes down, what breaks?\n- What is connected to the CRM?\n- Which resources are hidden, diagnostic-only, or currently relevant to this trace?\n\nAccess Command View through the Knowledge area at /knowledge/command-view.\n\nHow Command View Works\n\nCommand View is a visualization layer over the organization deployment manifest.\n\ntypescript\nconst yourOrgRegistry: DeploymentSpec = {\n agents: [],\n workflows: [],\n triggers: [],\n integrations: [],\n humanCheckpoints: [],\n relationships: {},\n externalResources: []\n}\n\nArchitecture:\n\n1. Manifest declares resources and relationships.\n2. SDK deploy and API registration validate declared references.\n3. Pre-serialization computes graph data once.\n4. Frontend visualizes cached graph data.\n\nCommand View does not create routing. It displays declarations and runtime topology data.\n\nNode Types\n\n| Type | Purpose | Badge info |\n| --- | --- | --- |\n| Triggers | Entry points such as webhook, schedule, manual, or event triggers | Trigger type |\n| Agents | Autonomous AI resources | Tool count, Knowledge Map, memory |\n| Workflows | Multi-step orchestrations | Step count |\n| Integrations | External service connections | Connection status |\n| External resources | Third-party platforms such as n8n, Make, or Zapier | Platform name |\n| Human checkpoints | Human decision points | Approval required |\n\nNode badges:\n\n- Agents show tool count, Knowledge Map, and memory.\n- Workflows show step count.\n- Integrations show connection status.\n- Triggers show webhook, schedule, manual, or event type.\n- External resources show platform.\n\nEdge Types\n\n| Type | Meaning |\n| --- | --- |\n| Triggers | A trigger initiates a resource |\n| Invokes | A resource calls another resource |\n| Uses | A resource uses an integration |\n| Approval | A resource requests human approval |\n\nDeclaring Relationships\n\nInternal Resources\n\nUse relationships to declare what agents and workflows invoke or use.\n\ntypescript\nconst relationships: ResourceRelationships = {\n 'executive-agent': {\n triggers: {\n workflows: ['report-workflow'],\n agents: ['research-agent']\n },\n uses: {\n integrations: ['integration-gmail', 'integration-attio']\n }\n }\n}\n\nTriggers\n\nTriggers declare their own metadata, while routing is declared through relationships.\n\ntypescript\nconst triggers: TriggerDefinition[] = [\n {\n resourceId: 'webhook-customer-created',\n type: 'trigger',\n triggerType: 'webhook',\n name: 'Customer Created Webhook',\n description: 'Triggers when a customer is created in Shopify',\n status: 'prod',\n webhookPath: '/webhooks/customer-created'\n }\n]\n\nTrigger routing is not configured on the trigger object itself.\n\nExternal Resources\n\nExternal resources can declare what they trigger and which integrations they use.\n\ntypescript\nconst externalResources: ExternalResourceDefinition[] = [\n {\n resourceId: 'external-n8n-sync',\n type: 'external',\n platform: 'n8n',\n name: 'N8N Product Sync',\n description: 'Syncs product data from Shopify to internal database',\n status: 'prod',\n triggers: { workflows: ['internal-sync-workflow'] },\n uses: { integrations: ['integration-shopify'] }\n }\n]\n\nThese declarations document the relationship. They do not programmatically connect the external platform.\n\nHuman Checkpoints\n\nHuman checkpoints declare which resources request approval and where approval can route.\n\ntypescript\nconst humanCheckpoints: HumanCheckpointDefinition[] = [\n {\n resourceId: 'approval-sales',\n name: 'Sales Approval Queue',\n description: 'Human approval for sales proposals',\n status: 'prod',\n requestedBy: { agents: ['sales-agent'] },\n routesTo: { workflows: ['send-proposal-workflow'] }\n }\n]\n\nActual human approval decisions are runtime choices, not automatic routing from the declaration alone.\n\nValidation\n\nCommand View shows relationships validated during deploy and API registration.\n\nValidation checks:\n\n- Referenced resource IDs exist.\n- Agent and workflow IDs are unique.\n- External resource references are valid.\n- Human checkpoint routes exist.\n- Model configs have valid providers, models, and API key references.\n\nThese checks cover declared relationships and registry consistency. They do not infer every runtime execution.trigger(...) target, especially when the target is computed dynamically.\n\nWhen validation errors occur, API startup fails with a descriptive error such as:\n\ntext\nRegistryValidationError: [YourOrg] Resource 'my-agent' uses non-existent integration: integration-attio\n\nFix validation errors by updating the manifest to reference the correct IDs or by adding the missing resource definition.\n\nUsing Command View\n\nVisualization Features\n\nCommand View uses Cytoscape graph modes:\n\n- Map: keeps organization structure visible and honors hidden-resource visibility.\n- Trace: resolves directed paths and reveals resources for the active trace.\n- Impact: pivots around the selected node and reveals related resources for impact review.\n\nFilter panel capabilities:\n\n- Search across nodes, relationships, and IDs.\n- Filter by node kind, resource type, environment, topology presence, integrations, and resource facets.\n- Toggle resource visibility and diagnostic/testing resource visibility.\n- Show visible and hidden resource counts in the same control surface.\n\nHidden resource behavior:\n\n- Resource nodes are hidden by default so the organization structure remains readable.\n- Structural nodes remain visible as the navigation skeleton.\n- Selecting a visible node can reveal directly connected hidden resources.\n- Diagnostic and testing resources are hidden by default and can be revealed from the filter panel.\n\nExpand Around behavior:\n\n- Select a node, open Details, and use Expand Around to preview nearby graph context before revealing it.\n- Semantic presets cover coverage, operational dependencies, organization context, and impact paths.\n- Feature, surface, entity, and capability nodes default to Coverage.\n- Resource nodes default to Operational Dependencies.\n- Preview counts show hidden resources before Apply reveals the graph patch.\n\nRead-only constraints:\n\n- No drag and drop.\n- No connection editing.\n- No graph mutation from the visualization layer.\n\nManifest Debugging\n\nUse Command View to verify:\n\n1. Resources appear as nodes.\n2. Relationships show as edges.\n3. Integration connections exist.\n4. Trigger invocations are declared correctly.\n5. Orphaned resources are intentional.\n\nCommon issues:\n\n- Typo in a resource ID reference.\n- Missing relationship declaration.\n- Incorrect integration credential name.\n- External resource missing a bidirectional declaration.\n\nSystem Understanding\n\nUseful exploration questions:\n\n- What triggers this workflow?\n- What integrations does this agent use?\n- What happens after this approval?\n- If this integration fails, what breaks?\n\nVisual patterns:\n\n- Hub nodes with many connections indicate critical resources.\n- Linear chains show sequential workflows.\n- Branching shows conditional logic.\n- Isolated nodes may indicate unused resources.\n\nTroubleshooting\n\nEmpty Graph\n\nLikely causes:\n\n- Organization has no resources defined.\n- Search, environment, node kind, topology, or resource facet filters hide all graph elements.\n- Command View resources are hidden and no structural nodes match current filters.\n- Validation errors prevented serialization.\n\nCheck:\n\n1. API logs for validation errors.\n2. Network tab for the /api/command-view response.\n3. Manifest resources arrays.\n4. Filter panel visibility and filter state.\n\nFix:\n\n- Add resources to the manifest.\n- Fix validation errors.\n- Reveal resources or reset graph filters.\n\nMissing Edges\n\nLikely causes:\n\n- Relationship is not declared in the manifest.\n- Resource ID reference has a typo.\n- Validation passed but the relationship declaration is incomplete.\n\nCheck:\n\n1. Manifest relationships field.\n2. Resource ID spelling and case.\n3. API response includes both nodes.\n\nFix the relationship declaration in the manifest.\n\nNode Not Appearing\n\nLikely causes:\n\n- Resource is not in the correct manifest array.\n- Resource is hidden by visibility controls.\n- Status, resource type, topology, or facet filters exclude the node.\n- Duplicate ID caused validation failure.\n\nCheck:\n\n1. Manifest includes the resource in the correct array.\n2. Filter panel visibility and filter state.\n3. Resource status field.\n4. API logs for duplicate ID errors.\n\nFix by adding the resource, revealing resources, or resetting filters.\n\nValidation Errors on Startup\n\nCommon error shape:\n\ntext\nRegistryValidationError: [OrgName] Resource 'resource-id' uses non-existent integration: integration-name\n\nCommon causes:\n\n- Typo in integration credential name.\n- Resource referenced before definition.\n- Missing import.\n\nFix:\n\n- Verify credential names match integration definitions.\n- Ensure all resources exist in manifest arrays.\n- Check module dependency statements in the manifest module.\n\nBest Practices\n\nKeep relationships current when resources change:\n\n1. Add new tools, then update uses.integrations.\n2. Add workflow invocation, then update triggers.workflows.\n3. Add agent delegation, then update triggers.agents.\n4. Add approval gate, then update the human checkpoint requestedBy.\n\nUse descriptive IDs:\n\n- integration-shopify-store-alpha instead of integration-1.\n- trigger-customer-created-webhook instead of trigger-webhook.\n- approval-sales-proposals instead of approval-1.\n\nValidate early and often:\n\nbash\npnpm dev:api\n\nAPI startup runs registry validation. Fix validation errors immediately because they prevent graph visualization.\n\nReview Command View regularly to onboard team members, plan new features, trace execution paths, and audit integration dependencies.\n\nRelationship Enforcement\n\nRelationships are declarations, not routing.\n\n| Layer | What it does | Enforcement |\n| --- | --- | --- |\n| DeploymentSpec.relationships | Declares relationships such as workflow A triggers workflow B | Validated at startup so IDs must exist |\n| buildEdges() in serialization.ts | Serializes declarations into CommandViewEdge[] | Pure transformation, no runtime check |\n| Runtime workflow and agent code | Calls resources through execution.trigger(...) or equivalent wiring | Independent of declarations |\n\nThe Resource Registry validates that declared targets reference real resource IDs during deploy and registration. However, there is no guarantee that declared graph relationships match runtime reality. Code can call a resource that is not declared in relationships, and that runtime call will not fail solely because the declaration is missing.\n\nEnforcement status:\n\n| Category | Validated at startup | Matches runtime | Status |\n| --- | --- | --- | --- |\n| Resource IDs unique | Yes | Yes, because lookup works | Enforced |\n| Input schema matches execution interface | Yes | Yes, because validation uses it | Enforced |\n| Relationship targets exist | Yes | No, invocations can be dynamic strings | Partially enforced |\n| Trigger routing | No | No, webhook handlers can hardcode routes | Decorative |\n| Tool availability per agent | No | No, tools are built dynamically by factories | Decorative |\n| Model config | Yes | No, runtime selects from environment variables | Decorative |\n| Integration usage | Partially, IDs checked | No, credentials resolve at runtime | Decorative |\n\nNon-Executable Node Types\n\nTriggers, integrations, external resources, and human checkpoints are non-executable node types. They exist for Command View.\n\n- TriggerDefinition does not set up actual routing. Webhook routing is independent.\n- IntegrationDefinition is a credentials reference with provider and credentialName; it does not connect to a provider by itself.\n- ExternalResourceDefinition documents a third-party automation but has no programmatic link to that platform.\n- HumanCheckpointDefinition documents approval queues and routes. Actual routing is determined by human choice and workflow code.\n\nRuntime Relationship Guard\n\nThere is no general runtime guard that discovers every nested execution target at call time. Deployed SDK workers can invoke nested resources through execution.trigger(...) and the API dispatcher, so dynamic targets can drift from DeploymentSpec.relationships even when deploy-time validation passes.\n\nDeploy-Time Validation\n\nResources are deployed through elevasis-sdk deploy. The SDK includes relationships in DeployMetadata, validates the resulting DeploymentSpec locally, and the API validates the merged deployment before registerOrganization().\n\nKey files:\n\n- packages/sdk/src/cli/commands/deploy.ts\n- apps/api/src/deployments/service.ts\n- packages/core/src/platform/registry/validation.ts\n\nAccepted Decorative Gaps\n\nThese gaps are inherent to the architecture and cannot be fully validated at deploy time:\n\n- Runtime invocation drift, especially with computed target IDs.\n- Tool declarations, because agents build tools dynamically by factory.\n- Model config, because runtime LLM calls use environment variables.\n- External resource triggers, because routing lives in external platforms.\n\nRelated References\n\n- /knowledge read knowledge.platform-composition-patterns\n- /knowledge read knowledge.platform-integration-patterns\n- /knowledge read knowledge.platform-capabilities"
1462
+ summary: "Reference for Command View, the visual Organization Model graph surface that projects systems, resources, actions, entities, events, and policies into an explorable operational view.",
1463
+ bodyText: "Overview\n\nCommand View is the visual surface for the Organization Model graph. It projects the OM -- systems, resources, actions, entities, events, and policies -- into an explorable graph using the same node and edge taxonomy emitted by buildOrganizationGraph().\n\nIt answers operational questions such as:\n\n- What systems own which resources?\n- What does this agent map to in the OM?\n- Which actions affect which entities?\n- If a resource goes offline, what policies or actions reference it?\n- What events originate from this entity or resource?\n\nAccess Command View through the Knowledge area at /knowledge/command-view.\n\nHow Command View Works\n\nCommand View is a projection of the Organization Model graph, not a separate deployment manifest.\n\nThe OM resources domain is the single source of resource identity. The actions domain is the invokable semantic layer. The systems domain is the backbone. Command View merges the graph emitted by buildOrganizationGraph() with optional live Command View data (deployed resource metadata) to render a unified operational picture.\n\nGraph projection pipeline:\n\n1. Organization Model is authored in packages/elevasis-core/src/organization-model/.\n2. buildOrganizationGraph() projects the OM into typed nodes and edges.\n3. Command View data (deployed resource metadata) is optionally merged as an overlay.\n4. The merged graph is serialized and cached.\n5. The frontend visualizes the cached graph.\n\nCommand View does not own resource identity. It reads what the OM declares.\n\nNode Kinds\n\nCommand View renders the same node kinds as the OM graph:\n\n| Kind | Source | Description |\n| -------------- | -------------- | -------------------------------------------------------------------------- |\n| organization | Root | The organization-model root node |\n| system | OM.systems | Bounded contexts with dotted IDs and parentSystemId hierarchy |\n| role | OM.roles | Named roles with hierarchy and holder assignments |\n| action | OM.actions | Invokable operations with invocation type metadata |\n| entity | OM.entities | Business objects owned by systems |\n| event | Projected | Derived from resource emits declarations and entity state catalogs |\n| policy | OM.policies | Governance rules applied to systems, actions, resources, and roles |\n| stage | Projected | Derived from prospecting stage catalogs |\n| resource | OM.resources | Workflows, agents, integrations, triggers, scripts, and external resources |\n| knowledge | OM.knowledge | Knowledge nodes governed by systems |\n\nThe resourceType overlay on resource nodes is a separate enum: workflow, agent, trigger, integration, external, humancheckpoint, script.\n\nEdge Kinds\n\n| Kind | Meaning |\n| ----------------- | ------------------------------------------------------------------------------ |\n| contains | Parent-to-child containment (organization to system, system to resource, etc.) |\n| references | Cross-reference between nodes (role reports-to, agent invokes action) |\n| mapsto | Action mapped to a resource implementation |\n| uses | System or stage uses an action |\n| governs | Knowledge node or role governs a system or target |\n| links | Entity links to another entity |\n| affects | Action affects an entity |\n| emits | Resource or entity emits an event |\n| originatesfrom | Event originates from an entity |\n| triggers | Event or action triggers a policy |\n| appliesto | Policy applies to a system, action, resource, or role |\n| effects | Policy effect invokes an action or notifies a role |\n\nVisualization Modes\n\nCommand View uses Cytoscape graph modes:\n\n- Map: preserves organization structure and honors hidden-resource visibility.\n- Trace: resolves directed paths and reveals resources for the active trace.\n- Impact: pivots around the selected node and reveals related resources for impact review.\n\nFilter panel:\n\n- Search across nodes, relationships, and IDs.\n- Filter by node kind, resource type, environment, topology presence, integrations, and resource facets.\n- Toggle resource visibility and diagnostic/testing resource visibility.\n- Show visible and hidden resource counts in the same control surface.\n\nHidden resource behavior:\n\n- Resource nodes are hidden by default so the organization structure remains readable.\n- Structural nodes remain visible as the navigation skeleton.\n- Selecting a visible node can reveal directly connected hidden resources.\n- Diagnostic and testing resources are hidden by default and can be revealed from the filter panel.\n\nExpand Around behavior:\n\n- Select a node, open Details, and use Expand Around to preview nearby graph context before revealing it.\n- Semantic presets cover coverage, operational dependencies, organization context, and impact paths.\n- System and entity nodes default to Coverage.\n- Resource nodes default to Operational Dependencies.\n- Preview counts show hidden resources before Apply reveals the graph patch.\n\nRead-only constraints:\n\n- No drag and drop.\n- No connection editing.\n- No graph mutation from the visualization layer.\n\nOrganization Model as the Source of Truth\n\nResource identity lives in OM.resources, not in a separate manifest. To add a resource to Command View:\n\n1. Add the resource to OM.resources in the organization model.\n2. Link it to a system via systemPath.\n3. Optionally link actions to the resource via action.resourceId.\n4. Deploy the organization model. Command View reflects the new resource automatically.\n\nThere is no separate DeploymentSpec.relationships declaration required for OM-declared resources. The graph builder derives containment and relationship edges directly from the OM contract.\n\nLive resource metadata (deployed name, description, runtime status) can be overlaid from Command View data when available, but the OM contract is primary.\n\nUsing Command View\n\nSystem Understanding\n\nUseful exploration questions:\n\n- What systems own which resources and entities?\n- What actions does this system expose, and what do they map to?\n- Which knowledge nodes govern this system?\n- What policies apply to this system?\n- What events originate from this entity?\n- What roles are responsible for this system?\n\nVisual patterns:\n\n- Hub nodes with many edges indicate central resources or pivotal systems.\n- Linear chains show sequential workflow pipelines.\n- Branching shows conditional routing or multiple action paths.\n- Isolated nodes may indicate unused or draft resources.\n\nManifest Debugging\n\nUse Command View to verify:\n\n1. Resources appear as nodes under the correct system.\n2. Actions map to the expected resources.\n3. Entities link to the correct systems and each other.\n4. Policies apply to the correct systems, actions, or resources.\n5. Events appear for resources with emits declarations.\n6. Orphaned resources are intentional.\n\nCommon issues:\n\n- Resource declared in OM but assigned to the wrong systemPath.\n- Action resourceId points to a resource ID that does not exist.\n- Entity ownedBySystemId references an unknown system.\n- Policy appliesTo references a system, action, or resource that was removed.\n\nTroubleshooting\n\nEmpty Graph\n\nLikely causes:\n\n- Organization has no systems or resources defined.\n- Search, node kind, or resource type filters hide all graph elements.\n- Command View resources are hidden and no structural nodes match current filters.\n\nCheck:\n\n1. OM systems and resources domains have entries.\n2. Filter panel visibility and filter state.\n3. API response for the /api/command-view endpoint.\n\nFix:\n\n- Add systems and resources to the organization model.\n- Reveal resources or reset graph filters.\n\nMissing Nodes\n\nLikely causes:\n\n- Resource, action, or entity is defined in OM but omitted from the relevant domain map.\n- Node is hidden by visibility controls.\n- Status, resource type, or topology filters exclude the node.\n\nCheck:\n\n1. OM domain map includes the ID as a key and as id in the entry.\n2. Filter panel visibility and filter state.\n3. Node lifecycle or enabled field.\n\nFix by adding the entry to the correct domain map or revealing hidden nodes.\n\nMissing Edges\n\nLikely causes:\n\n- Action resourceId does not match any OM resource ID.\n- Entity ownedBySystemId references an unknown system.\n- Policy appliesTo references IDs that do not exist.\n- Knowledge node link uses a nodeId that has no matching OM node.\n\nCheck:\n\n1. Cross-reference IDs across OM domains.\n2. Run pnpm --filter @repo/core check-types to surface Zod validation errors.\n\nFix the OM entry to reference the correct ID.\n\nBest Practices\n\nKeep the OM up to date as systems and resources evolve:\n\n1. Add new resources to OM.resources with the correct systemPath.\n2. Map actions to resources via action.resourceId when the action calls a specific resource.\n3. Update entity.ownedBySystemId when entities move between systems.\n4. Update policy.appliesTo when systems, actions, or resources are renamed or removed.\n5. Declare resource.emits for workflows and agents that produce observable events.\n\nUse the OM graph as the authoritative reference for Command View structure. The graph builder derives the visualization from the OM contract -- do not expect Command View to show connections that are not declared in the OM.\n\nRelated References\n\n- /knowledge read knowledge.org-model-reference\n- /knowledge read knowledge.platform-composition-patterns\n- /knowledge read knowledge.platform-integration-patterns"
2152
1464
  },
2153
1465
  {
2154
1466
  id: "knowledge.platform-composition-patterns",
@@ -2160,76 +1472,8 @@ Pre-Recording Checklist
2160
1472
  id: "knowledge.platform-integration-patterns",
2161
1473
  title: "Platform Integration Patterns",
2162
1474
  summary: "Reference for connecting Elevasis agents and workflows to external services through adapters, OAuth, API keys, tenant-isolated credentials, retries, and tests.",
2163
- bodyText: "Overview\n\nIntegration patterns define how Elevasis agents and workflows connect to external services such as Gmail, Attio, Google Sheets, and custom APIs. The platform uses a standardized adapter pattern with OAuth 2.0 and API key authentication backed by tenant-isolated credentials.\n\nCore patterns:\n\n- Direct integration, where a resource uses integration tools directly.\n- Integration workflow, where a workflow coordinates multiple integrations.\n- Shared integration, where multiple resources use the same credential set.\n- Multi-account integration, where the same provider has separate credentials for different contexts.\n\nDirect Integration Pattern\n\nPattern: Resource uses an integration tool.\n\nUse direct integration tools when an agent or workflow performs frequent operations against a provider.\n\nCharacteristics:\n\n- Tools are always available to the resource.\n- There is no additional navigation overhead.\n- The pattern is optimized for frequent read-heavy operations.\n\nTool factory location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-tools.ts\n\nTool factories use createIntegrationTool() with a credentialName parameter. Example: createAttioCreateRecordTool(credentialName).\n\nIntegration Workflow Pattern\n\nPattern: Agent invokes a workflow, and the workflow uses integrations.\n\nUse an integration workflow for complex multi-step operations that need deterministic orchestration.\n\nExample lead capture flow:\n\n1. Webhook trigger receives the event.\n2. Workflow creates an Attio contact.\n3. Workflow sends a Gmail notification.\n4. Workflow returns confirmation.\n\nCharacteristics:\n\n- Deterministic execution order.\n- Step-level error handling and retry.\n- Multiple integrations coordinated in one place.\n- Built-in audit trail through workflow execution.\n\nShared Integration Pattern\n\nPattern: Multiple resources share the same integration.\n\nUse shared integrations for organization-wide providers that should use one credential set.\n\nExample:\n\ntext\npackages/elevasis-operations/src/index.ts\n\nCharacteristics:\n\n- One credential per integration.\n- Centralized credential management.\n- Shared across agents and workflows.\n\nMulti-Account Pattern\n\nPattern: Same provider, different credentials.\n\nUse this pattern for department-specific provider instances or separate dev/prod environments.\n\nExample:\n\ntypescript\nconst salesTool = createAttioCreateRecordTool('attio-sales')\nconst supportTool = createAttioCreateRecordTool('attio-support')\n\nDisambiguate multi-account tools with explicit tool names:\n\ntypescript\nconst tool = createAttioToolNamed(\n 'attiosalescreaterecord',\n 'attio-sales',\n 'createRecord'\n)\n\nAuthentication Patterns\n\nOAuth 2.0 vs API Key\n\n| Aspect | OAuth 2.0 | API key |\n| --- | --- | --- |\n| Auth flow | Browser redirect plus token exchange | Direct API key |\n| Setup complexity | High: client ID, secret, redirect URL | Low: single API key |\n| Token refresh | Automatic refresh token rotation | Manual key rotation |\n| Scope control | Granular permission scopes | Full access or none |\n| User context | Per-user authorization | Service-level access |\n| Revocation | User can revoke anytime | Manual key deletion |\n\nOAuth 2.0 Pattern\n\nProviders include Gmail and Google Sheets.\n\nCredential format:\n\ntypescript\ninterface OAuthToken {\n provider: string\n accessToken: string\n refreshToken: string\n expiresAt: string\n tokenType: 'Bearer'\n scope?: string\n}\n\nexpiresAt is an ISO 8601 timestamp. The platform handles token refresh when supported by the provider and credential implementation.\n\nAPI Key Pattern\n\nProviders include Attio and custom APIs.\n\nCredential format:\n\ntypescript\ninterface APIKeyCredentials {\n apiKey: string\n}\n\nProvider-specific validation belongs in the adapter. For Attio, see:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/attio/attio-adapter.ts\n\nCredential Management\n\nCredentials are stored in the credentials table.\n\nKey columns:\n\n- organizationid for tenant isolation.\n- name, such as elevasis-attio.\n- provider, such as gmail or attio.\n- encryptedvalue containing encrypted JSON.\n\nSecurity rules:\n\n- RLS policies enforce tenant isolation.\n- Values are encrypted at rest.\n- Credentials do not cross organization boundaries.\n\nBest practices:\n\n- Store credentials encrypted in the database.\n- Use tenant-isolated credential names.\n- Validate credentials before API calls.\n- Rotate API keys regularly.\n- Use least-privilege OAuth scopes.\n\nDo not:\n\n- Hardcode credentials in code.\n- Share credentials across organizations.\n- Log credential values.\n- Store provider API keys in environment variables for tenant integrations.\n- Reuse the same credential name for dev and prod.\n\nCredential resolution flow:\n\n1. Tool requests a credential by name.\n2. Platform queries credentials with the current organizationid.\n3. Platform decrypts the credential.\n4. Adapter validates the credential against the provider schema.\n5. Tool passes the credential to the provider adapter.\n6. Usage is logged without credential values.\n\nImplementation reference:\n\ntext\npackages/core/src/execution/engine/tools/integration/tool.ts\n\nError Handling Patterns\n\nAdapters should convert provider errors into platform tooling errors.\n\nCommon error categories:\n\n- credentialsinvalid for invalid or missing credentials.\n- apierror for provider API errors.\n- networkerror for network or timeout failures.\n- validationerror for invalid parameters.\n- methodnotfound for unknown adapter methods.\n\nRetry strategy:\n\n- Network errors: retry with exponential backoff, commonly 1, 2, and 4 seconds.\n- Auth errors: fail immediately because the credential needs attention.\n- Validation errors: fail immediately because the input needs correction.\n- Rate limits: retry after reset when the provider exposes a reset time.\n- Workflow-level retries: commonly 3 attempts with 1, 4, and 9 minute delays.\n\nAdapter Development\n\nAdapter class location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-adapter.ts\n\nAdapter classes implement BaseIntegrationAdapter and contain call() and validateCredentials() methods.\n\nTool factory location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-tools.ts\n\nTool factories export create{Provider}{Operation}Tool(credentialName) functions.\n\nTests belong under:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/tests/\n\nRegistration happens in:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/index.ts\n\nTesting Strategies\n\nUnit testing:\n\n- Mock external APIs.\n- Cover credential validation.\n- Cover API call construction.\n- Cover response parsing.\n- Cover error handling.\n\nIntegration testing:\n\n- Use real API calls only with test accounts or test workspaces.\n- Clean up test data after tests.\n- Run in CI only when secret credentials are available.\n- Keep provider behavior mocked in unit tests.\n\nAgent testing:\n\n- Test agents using integration tools at the resource boundary.\n- Tenant project agent tests normally live under external/{org}/src/agents/{agent}/tests/.\n\nRelated References\n\n- /knowledge read knowledge.platform-composition-patterns\n- /knowledge read knowledge.platform-command-view\n- /knowledge read knowledge.platform-capabilities"
1475
+ bodyText: "Overview\n\nIntegration patterns define how Elevasis agents and workflows connect to external services such as Gmail, Attio, Google Sheets, and custom APIs. The platform uses a standardized adapter pattern with OAuth 2.0 and API key authentication backed by tenant-isolated credentials.\n\nCore patterns:\n\n- Direct integration, where a resource uses integration tools directly.\n- Integration workflow, where a workflow coordinates multiple integrations.\n- Shared integration, where multiple resources use the same credential set.\n- Multi-account integration, where the same provider has separate credentials for different contexts.\n\nDirect Integration Pattern\n\nPattern: Resource uses an integration tool.\n\nUse direct integration tools when an agent or workflow performs frequent operations against a provider.\n\nCharacteristics:\n\n- Tools are always available to the resource.\n- There is no additional navigation overhead.\n- The pattern is optimized for frequent read-heavy operations.\n\nTool factory location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-tools.ts\n\nTool factories use createIntegrationTool() with a credentialName parameter. Example: createAttioCreateRecordTool(credentialName).\n\nIntegration Workflow Pattern\n\nPattern: Agent invokes a workflow, and the workflow uses integrations.\n\nUse an integration workflow for complex multi-step operations that need deterministic orchestration.\n\nExample lead capture flow:\n\n1. Webhook trigger receives the event.\n2. Workflow creates an Attio contact.\n3. Workflow sends a Gmail notification.\n4. Workflow returns confirmation.\n\nCharacteristics:\n\n- Deterministic execution order.\n- Step-level error handling and retry.\n- Multiple integrations coordinated in one place.\n- Built-in audit trail through workflow execution.\n\nShared Integration Pattern\n\nPattern: Multiple resources share the same integration.\n\nUse shared integrations for organization-wide providers that should use one credential set.\n\nExample:\n\ntext\npackages/elevasis-operations/src/index.ts\n\nCharacteristics:\n\n- One credential per integration.\n- Centralized credential management.\n- Shared across agents and workflows.\n\nMulti-Account Pattern\n\nPattern: Same provider, different credentials.\n\nUse this pattern for department-specific provider instances or separate dev/prod environments.\n\nExample:\n\ntypescript\nconst salesTool = createAttioCreateRecordTool('attio-sales')\nconst supportTool = createAttioCreateRecordTool('attio-support')\n\nDisambiguate multi-account tools with explicit tool names:\n\ntypescript\nconst tool = createAttioToolNamed(\n 'attiosalescreaterecord',\n 'attio-sales',\n 'createRecord'\n)\n\nAuthentication Patterns\n\nOAuth 2.0 vs API Key\n\n| Aspect | OAuth 2.0 | API key |\n| --- | --- | --- |\n| Auth flow | Browser redirect plus token exchange | Direct API key |\n| Setup complexity | High: client ID, secret, redirect URL | Low: single API key |\n| Token refresh | Automatic refresh token rotation | Manual key rotation |\n| Scope control | Granular permission scopes | Full access or none |\n| User context | Per-user authorization | Service-level access |\n| Revocation | User can revoke anytime | Manual key deletion |\n\nOAuth 2.0 Pattern\n\nProviders include Gmail and Google Sheets.\n\nCredential format:\n\ntypescript\ninterface OAuthToken {\n provider: string\n accessToken: string\n refreshToken: string\n expiresAt: string\n tokenType: 'Bearer'\n scope?: string\n}\n\nexpiresAt is an ISO 8601 timestamp. The platform handles token refresh when supported by the provider and credential implementation.\n\nAPI Key Pattern\n\nProviders include Attio and custom APIs.\n\nCredential format:\n\ntypescript\ninterface APIKeyCredentials {\n apiKey: string\n}\n\nProvider-specific validation belongs in the adapter. For Attio, see:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/attio/attio-adapter.ts\n\nCredential Management\n\nCredentials are stored in the credentials table.\n\nKey columns:\n\n- organizationid for tenant isolation.\n- name, such as elevasis-attio.\n- provider, such as gmail or attio.\n- encryptedvalue containing encrypted JSON.\n\nSecurity rules:\n\n- RLS policies enforce tenant isolation.\n- Values are encrypted at rest.\n- Credentials do not cross organization boundaries.\n\nBest practices:\n\n- Store credentials encrypted in the database.\n- Use tenant-isolated credential names.\n- Validate credentials before API calls.\n- Rotate API keys regularly.\n- Use least-privilege OAuth scopes.\n\nDo not:\n\n- Hardcode credentials in code.\n- Share credentials across organizations.\n- Log credential values.\n- Store provider API keys in environment variables for tenant integrations.\n- Reuse the same credential name for dev and prod.\n\nCredential resolution flow:\n\n1. Tool requests a credential by name.\n2. Platform queries credentials with the current organizationid.\n3. Platform decrypts the credential.\n4. Adapter validates the credential against the provider schema.\n5. Tool passes the credential to the provider adapter.\n6. Usage is logged without credential values.\n\nImplementation reference:\n\ntext\npackages/core/src/execution/engine/tools/integration/tool.ts\n\nError Handling Patterns\n\nAdapters should convert provider errors into platform tooling errors.\n\nCommon error categories:\n\n- credentialsinvalid for invalid or missing credentials.\n- apierror for provider API errors.\n- networkerror for network or timeout failures.\n- validationerror for invalid parameters.\n- methodnotfound for unknown adapter methods.\n\nRetry strategy:\n\n- Network errors: retry with exponential backoff, commonly 1, 2, and 4 seconds.\n- Auth errors: fail immediately because the credential needs attention.\n- Validation errors: fail immediately because the input needs correction.\n- Rate limits: retry after reset when the provider exposes a reset time.\n- Workflow-level retries: commonly 3 attempts with 1, 4, and 9 minute delays.\n\nAdapter Development\n\nAdapter class location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-adapter.ts\n\nAdapter classes implement BaseIntegrationAdapter and contain call() and validateCredentials() methods.\n\nTool factory location:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/{provider}-tools.ts\n\nTool factories export create{Provider}{Operation}Tool(credentialName) functions.\n\nTests belong under:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/adapters/{provider}/tests/\n\nRegistration happens in:\n\ntext\npackages/core/src/execution/engine/tools/integration/server/index.ts\n\nTesting Strategies\n\nUnit testing:\n\n- Mock external APIs.\n- Cover credential validation.\n- Cover API call construction.\n- Cover response parsing.\n- Cover error handling.\n\nIntegration testing:\n\n- Use real API calls only with test accounts or test workspaces.\n- Clean up test data after tests.\n- Run in CI only when secret credentials are available.\n- Keep provider behavior mocked in unit tests.\n\nAgent testing:\n\n- Test agents using integration tools at the resource boundary.\n- Tenant project agent tests normally live under external/{org}/src/agents/{agent}/tests/.\n\nRelated References\n\n- /knowledge read knowledge.platform-composition-patterns\n- /knowledge read knowledge.platform-command-view\n- /knowledge read knowledge.platform-systems-overview"
2164
1476
  }
2165
1477
  ];
2166
- function buildSearchIndex(entries) {
2167
- return {
2168
- search(query) {
2169
- if (!query.trim()) return [];
2170
- const q = query.trim().toLowerCase();
2171
- const scored = [];
2172
- for (const entry of entries) {
2173
- let score = 0;
2174
- if (entry.title.toLowerCase().includes(q)) score += 3;
2175
- if (entry.summary.toLowerCase().includes(q)) score += 2;
2176
- if (entry.bodyText.toLowerCase().includes(q)) score += 1;
2177
- if (score > 0) scored.push({ id: entry.id, score });
2178
- }
2179
- return scored.sort((a, b) => b.score - a.score).map((s) => s.id);
2180
- }
2181
- };
2182
- }
2183
- function KnowledgeSearchBar({
2184
- knowledgeNodes,
2185
- onResults,
2186
- placeholder = "Search knowledge\u2026"
2187
- }) {
2188
- const [query, setQuery] = useState("");
2189
- const indexRef = useRef(null);
2190
- useEffect(() => {
2191
- indexRef.current = buildSearchIndex(knowledge_search_index_default);
2192
- }, []);
2193
- const nodeMapRef = useRef(/* @__PURE__ */ new Map());
2194
- useEffect(() => {
2195
- const map = /* @__PURE__ */ new Map();
2196
- for (const node of knowledgeNodes) map.set(node.id, node);
2197
- nodeMapRef.current = map;
2198
- }, [knowledgeNodes]);
2199
- const handleChange = (value) => {
2200
- setQuery(value);
2201
- if (!value.trim()) {
2202
- onResults(null);
2203
- return;
2204
- }
2205
- const ids = indexRef.current?.search(value) ?? [];
2206
- const hits = ids.flatMap((id) => {
2207
- const node = nodeMapRef.current.get(id);
2208
- return node ? [node] : [];
2209
- });
2210
- onResults(hits);
2211
- };
2212
- const handleClear = () => {
2213
- setQuery("");
2214
- onResults(null);
2215
- };
2216
- return /* @__PURE__ */ jsx(
2217
- TextInput,
2218
- {
2219
- value: query,
2220
- onChange: (e) => handleChange(e.currentTarget.value),
2221
- placeholder,
2222
- leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
2223
- rightSection: query ? /* @__PURE__ */ jsx(IconX, { size: 14, style: { cursor: "pointer", color: "var(--color-text-subtle)" }, onClick: handleClear }) : null,
2224
- styles: {
2225
- input: {
2226
- backgroundColor: "var(--color-surface)",
2227
- borderColor: "var(--color-border)",
2228
- color: "var(--color-text)"
2229
- }
2230
- }
2231
- }
2232
- );
2233
- }
2234
-
2235
- export { EdgeChip, EdgeGroup, EdgeRelationshipGroup, KNOWLEDGE_ICON_TOKEN_BY_KIND, KeyField, KindChip, KnowledgeSearchBar, KnowledgeTree, NodeDescribeShell, NodeHeader, NodeMetadataFooter, RelatedKnowledgeSection, byKind, getKnowledgeIconToken };
1478
+
1479
+ export { knowledge_search_index_default as default };