@kedem/okdb 1.0.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 (260) hide show
  1. package/LICENSE +57 -0
  2. package/README.md +344 -0
  3. package/banner.jpg +0 -0
  4. package/bin/okdb.js +2 -0
  5. package/docs/OKDB-ARCHITECTURE.md +1036 -0
  6. package/docs/auth-and-sync.md +558 -0
  7. package/docs/auth-permissions.md +143 -0
  8. package/docs/change-log.md +169 -0
  9. package/docs/data-model.md +174 -0
  10. package/docs/embeddings.md +338 -0
  11. package/docs/files.md +131 -0
  12. package/docs/fts.md +139 -0
  13. package/docs/functions.md +514 -0
  14. package/docs/getting-started.md +233 -0
  15. package/docs/http-api.md +705 -0
  16. package/docs/index.md +115 -0
  17. package/docs/indexes.md +207 -0
  18. package/docs/logging.md +116 -0
  19. package/docs/manifest.json +38 -0
  20. package/docs/migration.md +154 -0
  21. package/docs/pipelines.md +598 -0
  22. package/docs/plugins.md +144 -0
  23. package/docs/querying.md +204 -0
  24. package/docs/queue.md +637 -0
  25. package/docs/sync.md +156 -0
  26. package/docs/transactions.md +140 -0
  27. package/docs/ttl.md +375 -0
  28. package/okdb.js +1 -0
  29. package/package.json +26 -0
  30. package/public/admin-app.js +1 -0
  31. package/public/android-chrome-192x192.png +0 -0
  32. package/public/android-chrome-512x512.png +0 -0
  33. package/public/apple-touch-icon.png +0 -0
  34. package/public/components/admin-route-host.ok.js +1 -0
  35. package/public/components/env-picker.ok.js +1 -0
  36. package/public/components/field-path-input.ok.js +1 -0
  37. package/public/components/field.html +6 -0
  38. package/public/components/geo-map.ok.js +1 -0
  39. package/public/components/ok-cron-input.ok.js +1 -0
  40. package/public/components/ok-dropzone.ok.js +1 -0
  41. package/public/components/ok-js-input.ok.js +1 -0
  42. package/public/components/ok-json-input.ok.js +1 -0
  43. package/public/components/ok-text-monaco-input.ok.js +1 -0
  44. package/public/components/theme-toggle.ok.js +1 -0
  45. package/public/favicon-16x16.png +0 -0
  46. package/public/favicon-32x32.png +0 -0
  47. package/public/favicon.ico +0 -0
  48. package/public/images/logo.png +0 -0
  49. package/public/images/logo.svg +333 -0
  50. package/public/index.html +6 -0
  51. package/public/layouts/_default.ok.html +1 -0
  52. package/public/layouts/okdb-cube.ok.html +1 -0
  53. package/public/login-app.js +1 -0
  54. package/public/login.html +1 -0
  55. package/public/modules/ok.js +1 -0
  56. package/public/sections/api/index.ok.html +1 -0
  57. package/public/sections/api/parts/api-endpoint.ok.js +1 -0
  58. package/public/sections/auth/index.ok.html +1 -0
  59. package/public/sections/auth/modals/create-token-modal.ok.js +1 -0
  60. package/public/sections/auth/modals/edit-token-modal.ok.js +1 -0
  61. package/public/sections/auth/modals/perm-info-popover.ok.js +1 -0
  62. package/public/sections/auth/parts/token-detail.ok.js +1 -0
  63. package/public/sections/auth/parts/token-list.ok.js +1 -0
  64. package/public/sections/db/index.ok.html +1 -0
  65. package/public/sections/db/modals/add-item-modal.ok.js +1 -0
  66. package/public/sections/db/modals/create-env-modal.ok.js +1 -0
  67. package/public/sections/db/modals/create-fts-modal.ok.js +1 -0
  68. package/public/sections/db/modals/create-index-modal.ok.js +1 -0
  69. package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -0
  70. package/public/sections/db/modals/demo-env-modal.ok.js +1 -0
  71. package/public/sections/db/modals/remove-env-modal.ok.js +1 -0
  72. package/public/sections/db/modals/schema-edit-modal.ok.js +1 -0
  73. package/public/sections/db/parts/db-overview.ok.js +1 -0
  74. package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -0
  75. package/public/sections/db/parts/edit-row.ok.js +1 -0
  76. package/public/sections/db/parts/tm-timeline.ok.js +1 -0
  77. package/public/sections/db/parts/type-changelog.ok.js +1 -0
  78. package/public/sections/db/parts/type-list.ok.js +1 -0
  79. package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -0
  80. package/public/sections/db/parts/type-schema-tab.ok.js +1 -0
  81. package/public/sections/db/parts/type-viewer.ok.js +1 -0
  82. package/public/sections/db/parts/type-violations-tab.ok.js +1 -0
  83. package/public/sections/docs/index.ok.html +1 -0
  84. package/public/sections/embeddings/index.ok.html +1 -0
  85. package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -0
  86. package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -0
  87. package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -0
  88. package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -0
  89. package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -0
  90. package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -0
  91. package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -0
  92. package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -0
  93. package/public/sections/embeddings/parts/embed-overview.ok.js +1 -0
  94. package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -0
  95. package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -0
  96. package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -0
  97. package/public/sections/embeddings/parts/engines-overview.ok.js +1 -0
  98. package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -0
  99. package/public/sections/engines/engine-panel-shared-style.js +1 -0
  100. package/public/sections/engines/engine-ui-utils.js +1 -0
  101. package/public/sections/engines/index.ok.html +1 -0
  102. package/public/sections/engines/modals/engine-modal.ok.js +1 -0
  103. package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -0
  104. package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -0
  105. package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -0
  106. package/public/sections/engines/parts/engine-resource-card.ok.js +1 -0
  107. package/public/sections/engines/parts/engine-row-item.ok.js +1 -0
  108. package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -0
  109. package/public/sections/files/index.ok.html +1 -0
  110. package/public/sections/files/parts/files-blob-status.ok.js +1 -0
  111. package/public/sections/files/parts/files-collection-list.ok.js +1 -0
  112. package/public/sections/files/parts/files-collection-panel.ok.js +1 -0
  113. package/public/sections/files/parts/files-file-list.ok.js +1 -0
  114. package/public/sections/files/parts/files-overview.ok.js +1 -0
  115. package/public/sections/files/parts/files-path-browser.ok.js +1 -0
  116. package/public/sections/files/parts/files-upload-panel.ok.js +1 -0
  117. package/public/sections/functions/index.ok.html +1 -0
  118. package/public/sections/functions/modals/function-modal.ok.js +1 -0
  119. package/public/sections/functions/parts/function-detail.ok.js +1 -0
  120. package/public/sections/functions/parts/function-logs.ok.js +1 -0
  121. package/public/sections/functions/parts/function-runner.ok.js +1 -0
  122. package/public/sections/functions/parts/functions-list.ok.js +1 -0
  123. package/public/sections/license/index.ok.html +1 -0
  124. package/public/sections/license/parts/license-panel.ok.js +1 -0
  125. package/public/sections/processors/index.ok.html +1 -0
  126. package/public/sections/queue/index.ok.html +1 -0
  127. package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -0
  128. package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -0
  129. package/public/sections/queue/modals/edit-job-modal.ok.js +1 -0
  130. package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -0
  131. package/public/sections/queue/modals/job-type-modal.ok.js +1 -0
  132. package/public/sections/queue/parts/ok-job-form.ok.js +1 -0
  133. package/public/sections/queue/parts/queue-buckets.ok.js +1 -0
  134. package/public/sections/queue/parts/queue-job-types.ok.js +1 -0
  135. package/public/sections/queue/parts/queue-jobs.ok.js +1 -0
  136. package/public/sections/queue/parts/queue-types.ok.js +1 -0
  137. package/public/sections/queue/parts/queue-workers.ok.js +1 -0
  138. package/public/sections/sync/index.ok.html +5 -0
  139. package/public/sections/sync/parts/sync-node-detail.ok.js +1 -0
  140. package/public/sections/sync/parts/sync-retention.ok.js +1 -0
  141. package/public/sections/sync/parts/sync-topology.ok.js +1 -0
  142. package/public/sections/system/index.ok.html +1 -0
  143. package/public/sections/system/modals/data-ops-modal.ok.js +1 -0
  144. package/public/sections/system/parts/system-api-panel.ok.js +1 -0
  145. package/public/sections/system/parts/system-auth-panel.ok.js +1 -0
  146. package/public/sections/system/parts/system-log-history.ok.js +1 -0
  147. package/public/sections/system/parts/system-log.ok.js +1 -0
  148. package/public/sections/system/parts/system-status.ok.js +1 -0
  149. package/public/sections/system/parts/system-sync-panel.ok.js +1 -0
  150. package/public/sections/views/index.ok.html +1 -0
  151. package/public/sections/views/modals/create-view-modal.ok.js +1 -0
  152. package/public/sections/views/parts/view-detail.ok.js +1 -0
  153. package/public/sections/views/parts/views-list.ok.js +1 -0
  154. package/public/sections/views/parts/views-overview.ok.js +1 -0
  155. package/public/setup-app.js +1 -0
  156. package/public/setup.html +1 -0
  157. package/public/site.webmanifest +1 -0
  158. package/public/stores/auth-store.js +1 -0
  159. package/public/stores/events-store.js +1 -0
  160. package/public/stores/functions-store.js +1 -0
  161. package/public/stores/okdb-store.js +1 -0
  162. package/public/stores/theme-store.js +1 -0
  163. package/public/styles.css +1 -0
  164. package/public/test-cron-input.html +10 -0
  165. package/public/test-json-input.html +101 -0
  166. package/public/util/permissions.js +1 -0
  167. package/public/util/sift-schema.js +1 -0
  168. package/public/vendor/okjs/ok.esm.min.js +2 -0
  169. package/public/vendor/okjs/toolkit/behavior/async.ok.js +1 -0
  170. package/public/vendor/okjs/toolkit/components/ok-chart.ok.js +1 -0
  171. package/public/vendor/okjs/toolkit/components/ok-doc-viewer.ok.js +1 -0
  172. package/public/vendor/okjs/toolkit/components/ok-marked.ok.js +1 -0
  173. package/public/vendor/okjs/toolkit/components/ok-monaco.ok.js +1 -0
  174. package/public/vendor/okjs/toolkit/core/ok-layer-service.ok.js +1 -0
  175. package/public/vendor/okjs/toolkit/core/ok-layer.ok.js +1 -0
  176. package/public/vendor/okjs/toolkit/core/ok-overlay.ok.js +1 -0
  177. package/public/vendor/okjs/toolkit/core/ok-sandbox.ok.js +1 -0
  178. package/public/vendor/okjs/toolkit/core/transition.ok.js +1 -0
  179. package/public/vendor/okjs/toolkit/core/virtualized.ok.js +1 -0
  180. package/public/vendor/okjs/toolkit/devtools/ok-console-service.ok.js +1 -0
  181. package/public/vendor/okjs/toolkit/devtools/ok-console.ok.js +1 -0
  182. package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor-service.ok.js +1 -0
  183. package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor.ok.js +1 -0
  184. package/public/vendor/okjs/toolkit/devtools/ok-inspector-service.ok.js +1 -0
  185. package/public/vendor/okjs/toolkit/devtools/ok-inspector.ok.js +1 -0
  186. package/public/vendor/okjs/toolkit/devtools/ok-js-tree.ok.js +1 -0
  187. package/public/vendor/okjs/toolkit/devtools/ok-timeline-service.ok.js +1 -0
  188. package/public/vendor/okjs/toolkit/devtools/ok-timeline.ok.js +1 -0
  189. package/public/vendor/okjs/toolkit/docs/doc-viewer.ok.js +1 -0
  190. package/public/vendor/okjs/toolkit/editor/ok-live-component.ok.js +1 -0
  191. package/public/vendor/okjs/toolkit/editor/ok-live-example.ok.js +1 -0
  192. package/public/vendor/okjs/toolkit/editor/ok-live-shell.ok.js +1 -0
  193. package/public/vendor/okjs/toolkit/elements/ok-dropdown.ok.js +1 -0
  194. package/public/vendor/okjs/toolkit/elements/ok-icon.ok.js +1 -0
  195. package/public/vendor/okjs/toolkit/elements/ok-select.ok.js +1 -0
  196. package/public/vendor/okjs/toolkit/elements/ok-table.ok.js +1 -0
  197. package/public/vendor/okjs/toolkit/errors/ok-crash-boundary.ok.js +1 -0
  198. package/public/vendor/okjs/toolkit/errors/ok-crash-info.ok.js +1 -0
  199. package/public/vendor/okjs/toolkit/i18n/i18n-editor-examples.ok.js +1 -0
  200. package/public/vendor/okjs/toolkit/i18n/i18n-editor.ok.js +1 -0
  201. package/public/vendor/okjs/toolkit/i18n/i18n-key-editor-tips.ok.js +1 -0
  202. package/public/vendor/okjs/toolkit/i18n/i18n-key-editor.ok.js +1 -0
  203. package/public/vendor/okjs/toolkit/i18n/i18n-service.ok.js +1 -0
  204. package/public/vendor/okjs/toolkit/i18n/ok-i18n.js +1 -0
  205. package/public/vendor/okjs/toolkit/interaction/ok-contextmenu.ok.js +1 -0
  206. package/public/vendor/okjs/toolkit/interaction/ok-dismiss-service.ok.js +1 -0
  207. package/public/vendor/okjs/toolkit/interaction/ok-draggable.ok.js +1 -0
  208. package/public/vendor/okjs/toolkit/interaction/ok-flyover-panel.ok.js +1 -0
  209. package/public/vendor/okjs/toolkit/interaction/ok-flyover.ok.js +1 -0
  210. package/public/vendor/okjs/toolkit/interaction/ok-highlight-service.ok.js +1 -0
  211. package/public/vendor/okjs/toolkit/interaction/ok-highlight.ok.js +1 -0
  212. package/public/vendor/okjs/toolkit/interaction/ok-hotkeys-service.ok.js +1 -0
  213. package/public/vendor/okjs/toolkit/interaction/ok-picker-service.ok.js +1 -0
  214. package/public/vendor/okjs/toolkit/interaction/ok-popout-service.ok.js +1 -0
  215. package/public/vendor/okjs/toolkit/interaction/ok-popout.ok.js +1 -0
  216. package/public/vendor/okjs/toolkit/interaction/ok-portal-service.ok.js +1 -0
  217. package/public/vendor/okjs/toolkit/interaction/ok-submenu.ok.js +1 -0
  218. package/public/vendor/okjs/toolkit/layout/ok-resizer.ok.js +1 -0
  219. package/public/vendor/okjs/toolkit/manifest.js +1 -0
  220. package/public/vendor/okjs/toolkit/modals/ok-modal-service.ok.js +1 -0
  221. package/public/vendor/okjs/toolkit/modals/ok-modal.ok.js +1 -0
  222. package/public/vendor/okjs/toolkit/modals/ok-toast-service.ok.js +1 -0
  223. package/public/vendor/okjs/toolkit/modals/ok-window.ok.js +1 -0
  224. package/public/vendor/okjs/toolkit/navigation/hash-router.ok.js +1 -0
  225. package/public/vendor/okjs/toolkit/navigation/history-router.ok.js +1 -0
  226. package/public/vendor/okjs/toolkit/navigation/router.ok.js +1 -0
  227. package/public/vendor/okjs/toolkit/sync/reactive-sync-service.ok.js +1 -0
  228. package/public/vendor/okjs/toolkit/sync/reactive-sync.js +1 -0
  229. package/public/vendor/okjs/toolkit/theming/blocks/ok-design-button.css.js +1 -0
  230. package/public/vendor/okjs/toolkit/theming/blocks/ok-design-input.css.js +1 -0
  231. package/public/vendor/okjs/toolkit/theming/ok-design-style.js +1 -0
  232. package/public/vendor/okjs/toolkit/theming/ok-design-vars.js +1 -0
  233. package/public/vendor/okjs/toolkit/theming/ok-design.ok.js +1 -0
  234. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-input.ok.js +1 -0
  235. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-service.ok.js +1 -0
  236. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-style.js +1 -0
  237. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-utils.js +1 -0
  238. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-variable.ok.js +1 -0
  239. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-vm.js +1 -0
  240. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor.ok.js +1 -0
  241. package/public/vendor/okjs/toolkit/theming/ok-theme.ok.js +1 -0
  242. package/public/view-models/type-query-vm.js +1 -0
  243. package/types/environment.d.ts +130 -0
  244. package/types/errors.d.ts +98 -0
  245. package/types/features/admin.d.ts +4 -0
  246. package/types/features/api.d.ts +18 -0
  247. package/types/features/auth.d.ts +31 -0
  248. package/types/features/embeddings.d.ts +39 -0
  249. package/types/features/engines.d.ts +23 -0
  250. package/types/features/files.d.ts +29 -0
  251. package/types/features/fts.d.ts +25 -0
  252. package/types/features/functions.d.ts +23 -0
  253. package/types/features/mcp.d.ts +17 -0
  254. package/types/features/pipelines.d.ts +19 -0
  255. package/types/features/queue.d.ts +189 -0
  256. package/types/features/sync.d.ts +34 -0
  257. package/types/features/time-machine.d.ts +32 -0
  258. package/types/features/views.d.ts +16 -0
  259. package/types/index.d.ts +153 -0
  260. package/types/options.d.ts +202 -0
@@ -0,0 +1,598 @@
1
+ # Pipelines
2
+
3
+ OKDB now has a base `pipelines` feature for storing environment-defined engine topologies in a synced `~pipelines` registry.
4
+
5
+ This is the generic layer above `engines`.
6
+
7
+ - engines remain standalone runtime units
8
+ - pipelines group engines structurally
9
+ - pipeline records live in the environment that defines them
10
+ - pipeline records sync like other env data
11
+
12
+ ---
13
+
14
+ ## V1 record shape
15
+
16
+ ```javascript
17
+ {
18
+ name: 'articles-ingest',
19
+ template: null,
20
+ status: 'active', // 'active' | 'stopped'
21
+ meta: { label: 'Articles ingest' },
22
+ created: 1710000000000,
23
+ updated: 1710000000000,
24
+ engines: [
25
+ { type: 'embedder', name: 'shared-embedder', role: 'embedder' },
26
+ { type: 'indexer', name: 'analytics:articles-ingest', role: 'indexer' },
27
+ { type: 'vector-search', name: 'analytics:articles-ingest', role: 'search' },
28
+ ],
29
+ }
30
+ ```
31
+
32
+ Rules in V1:
33
+
34
+ - `name` is required and must be a non-empty string
35
+ - `template` must be `null`
36
+ - `status` must be `active` or `stopped`
37
+ - `engines` must be a non-empty ordered array
38
+ - every engine entry must have non-empty `type`, `name`, and `role`
39
+ - engine order is meaningful and preserved
40
+
41
+ ---
42
+
43
+ ## Where records live
44
+
45
+ Pipelines are environment-defined.
46
+
47
+ That means:
48
+
49
+ - `okdb.env('analytics').pipelines.create(...)` stores in `analytics` env `~pipelines`
50
+ - synced peers receive the record in that same env
51
+ - `okdb.pipelines.list()` aggregates pipeline records across opened envs
52
+
53
+ Unlike env-scoped engines, pipelines do **not** use `~system` by default.
54
+
55
+ ---
56
+
57
+ ## Current SDK surface
58
+
59
+ ### Env-local facade
60
+
61
+ ```javascript
62
+ const analytics = okdb.env('analytics');
63
+
64
+ // Engines must already exist before a V1 pipeline record can be created.
65
+ await analytics.pipelines.create({
66
+ name: 'articles-ingest',
67
+ template: null,
68
+ status: 'active',
69
+ meta: {},
70
+ engines: [
71
+ { type: 'embedder', name: 'shared-embedder', role: 'embedder' },
72
+ { type: 'indexer', name: 'analytics:articles-ingest', role: 'indexer' },
73
+ ],
74
+ });
75
+
76
+ const record = await analytics.pipelines.get('articles-ingest');
77
+ const all = await analytics.pipelines.list();
78
+
79
+ await analytics.pipelines.stop('articles-ingest');
80
+ await analytics.pipelines.start('articles-ingest');
81
+ await analytics.pipelines.remove('articles-ingest');
82
+ ```
83
+
84
+ ### HTTP API surface
85
+
86
+ The generic pipeline registry is also exposed over HTTP:
87
+
88
+ ```text
89
+ GET /api/pipelines/templates
90
+ GET /api/pipelines/templates/:template
91
+ POST /api/pipelines/templates/:template/preview
92
+ GET /api/pipelines
93
+ GET /api/env/:env/pipelines
94
+ GET /api/env/:env/pipelines/:pipeline
95
+ POST /api/env/:env/pipelines
96
+ POST /api/env/:env/pipelines/templates/:template/create
97
+ POST /api/env/:env/pipelines/scaffold
98
+ POST /api/env/:env/pipelines/:pipeline/start
99
+ POST /api/env/:env/pipelines/:pipeline/stop
100
+ DELETE /api/env/:env/pipelines/:pipeline
101
+ ```
102
+
103
+ - `GET /api/pipelines/templates` lists starter recommendations for both generic and embeddings pipeline families
104
+ - `GET /api/pipelines/templates/:template` returns one pipeline starter definition, including its input schema, defaults, `family`, and `recommended` flag
105
+ - `POST /api/pipelines/templates/:template/preview` expands a starter into the exact plan it would execute without persisting anything
106
+ - `POST /api/env/:env/pipelines/templates/:template/create` expands a starter template and executes the underlying scaffold/create operation
107
+ - `POST /api/env/:env/pipelines` expects referenced engines to already exist
108
+ - `POST /api/env/:env/pipelines/scaffold` is the convenience path that creates env-owned engines and then creates the pipeline record atomically
109
+ - `GET /api/pipelines` aggregates generic pipeline records across all currently opened environments
110
+
111
+ The pipeline template routes are a filtered view over the broader shared template registry exposed at `GET /api/engines/templates`:
112
+
113
+ - `/api/pipelines/templates` only returns entries with `kind: "pipeline"`
114
+ - generic starters currently include `generic-processor`, `generic-materializer`, and `generic-queue-worker`
115
+ - embeddings starters currently include `embeddings-inline-fake`, `embeddings-inline-ollama`, `embeddings-queue-fake`, and `embeddings-queue-ollama`
116
+
117
+ Template execution depends on the selected family:
118
+
119
+ - generic pipeline templates use the same atomic scaffold flow as `POST /api/env/:env/pipelines/scaffold`
120
+ - embeddings pipeline templates delegate to `okdb.embeddings.createPipeline(...)` and then return the resulting generic `~pipelines` record
121
+ - both flows stamp `meta.templateId` so the resulting record keeps template provenance
122
+
123
+ For embeddings-backed templates, remember that the persisted generic pipeline record name is the resolved `storage_key` (defaulting to the supplied pipeline `name`). The template response still returns the user-facing label through `meta.label`.
124
+
125
+ ### MCP surface
126
+
127
+ The grouped `okdb_pipeline` tool intentionally separates the two pipeline families:
128
+
129
+ - generic pipeline registry actions are exposed as `generic_list_all`, `generic_list`, `generic_get`, `generic_create`, `generic_start`, `generic_stop`, `generic_delete`, and `generic_scaffold`
130
+ - embeddings env/type pipeline actions keep concise names such as `list`, `stats`, `query`, `start`, `stop`, and `delete`
131
+ - starter template actions are exposed as `template_list`, `template_get`, `template_preview`, and `template_create`
132
+
133
+ For MCP ergonomics, bare `list` also has a convenience fallback:
134
+
135
+ - `action: "list", env: "analytics", type: "articles"` → embeddings env/type pipeline summaries
136
+ - `action: "list", env: "analytics"` → the same env-scoped generic registry view as `generic_list`
137
+
138
+ In practice that means an MCP client can:
139
+
140
+ - call `template_list` to discover recommended starters
141
+ - call `template_preview` to inspect the concrete scaffold or embeddings-create plan
142
+ - call `template_create` to execute that plan in a target environment
143
+
144
+ Direct engine discovery/creation now lives in the dedicated `okdb_engine` tool instead:
145
+
146
+ - `action: "types"` lists registered engine kinds and their self-declared config metadata
147
+ - `action: "create"` creates a direct env-scoped engine without a pipeline record
148
+ - `action: "list" | "get" | "patch" | "delete" | "restart" | "pause" | "resume" | "retry" | "reset_cursor" | "rebuild"` manages existing direct engines
149
+
150
+ ### Generic `queue-worker` engine
151
+
152
+ Step 04 adds a generic `queue-worker` engine type that can run standalone or participate as a reusable pipeline member.
153
+
154
+ In V1 it is:
155
+
156
+ - standalone-capable
157
+ - pipeline-compatible
158
+ - queue-backed
159
+ - function-driven
160
+
161
+ Typical flow:
162
+
163
+ ```javascript
164
+ const analytics = okdb.env('analytics');
165
+
166
+ await analytics.functions.create({
167
+ name: 'processArticleJob',
168
+ source: `async (ctx) => {
169
+ await ctx.env.ensureType('worker_results');
170
+ await ctx.env.put('worker_results', String(ctx.payload.id), { ok: true });
171
+ return { ok: true };
172
+ }`,
173
+ });
174
+
175
+ await analytics.engines.createAndStartEngine('queue-worker', 'articles-worker', {
176
+ job_type: 'article-ingest',
177
+ handler: { kind: 'function', name: 'processArticleJob' },
178
+ pollInterval: 100,
179
+ concurrency: 2,
180
+ });
181
+
182
+ await analytics.pipelines.create({
183
+ name: 'articles-ingest',
184
+ template: null,
185
+ status: 'active',
186
+ meta: { label: 'Articles ingest' },
187
+ engines: [{ type: 'queue-worker', name: 'articles-worker', role: 'worker' }],
188
+ });
189
+
190
+ await analytics.queue.enqueue('article-ingest', { id: 'job-1' });
191
+ ```
192
+
193
+ `queue-worker` config shape in V1:
194
+
195
+ ```javascript
196
+ {
197
+ job_type: 'article-ingest',
198
+ queue_env: 'analytics', // optional, defaults to the engine owning env
199
+ handler: {
200
+ kind: 'function',
201
+ name: 'processArticleJob',
202
+ env: 'analytics', // optional, defaults to the engine owning env
203
+ },
204
+ concurrency: 2,
205
+ pollInterval: 100,
206
+ ttl: 30000,
207
+ }
208
+ ```
209
+
210
+ Config notes:
211
+
212
+ - `job_type` — queue job type to consume
213
+ - `handler.kind` — currently must be `"function"`
214
+ - `handler.name` — function to invoke for each claimed payload
215
+ - `queue_env` — optional env name for the queue source; defaults to the engine owning env
216
+ - `handler.env` — optional env name for the function registry; defaults to the engine owning env
217
+ - `concurrency`, `pollInterval`, `ttl` — forwarded to the underlying queue worker runtime
218
+
219
+ The function runner pool scales dynamically to match `concurrency` — no pool configuration is needed.
220
+
221
+ Behavior:
222
+
223
+ - claims jobs through the normal queue feature
224
+ - invokes the configured env function once per claimed payload
225
+ - completes or fails jobs using the same queue semantics as other queue workers
226
+ - can read from one env's queue while resolving the handler function from another env
227
+
228
+ Runtime stats exposed through `engine.api.stats()` include:
229
+
230
+ - `processed`
231
+ - `failed`
232
+ - `running`
233
+ - resolved `queue_env`
234
+ - resolved handler metadata
235
+
236
+ Minimal pipeline membership example:
237
+
238
+ ```javascript
239
+ await analytics.pipelines.create({
240
+ name: 'articles-ingest',
241
+ template: null,
242
+ status: 'active',
243
+ meta: { label: 'Articles ingest' },
244
+ engines: [{ type: 'queue-worker', name: 'articles-worker', role: 'worker' }],
245
+ });
246
+ ```
247
+
248
+ ### Generic `processor` engine
249
+
250
+ Step 05 adds a generic `processor` engine type for change-log driven pipeline members.
251
+
252
+ In V1 it is:
253
+
254
+ - standalone-capable
255
+ - pipeline-compatible
256
+ - built on the existing processor feature
257
+ - function-driven
258
+ - suitable for projection, transformation, and queue fan-out workflows
259
+
260
+ Typical flow:
261
+
262
+ ```javascript
263
+ const analytics = okdb.env('analytics');
264
+
265
+ await analytics.registerType('articles');
266
+
267
+ await analytics.functions.create({
268
+ name: 'projectArticleChanges',
269
+ source: `async (ctx) => {
270
+ await ctx.env.ensureType('article_projection');
271
+ for (const change of ctx.payload) {
272
+ if (change.action === 'put') {
273
+ await ctx.env.put('article_projection', change.key, {
274
+ title: change.value.title,
275
+ source_env: ctx.processor.sourceEnv,
276
+ });
277
+ }
278
+ }
279
+ return { processed: ctx.payload.length };
280
+ }`,
281
+ });
282
+
283
+ await analytics.engines.createAndStartEngine('processor', 'article-projector', {
284
+ source_type: 'articles',
285
+ handler: { kind: 'function', name: 'projectArticleChanges' },
286
+ bootstrap: 'log',
287
+ batchSize: 64,
288
+ });
289
+
290
+ await analytics.put('articles', 'a1', { title: 'Hello' });
291
+ ```
292
+
293
+ `processor` config shape in V1:
294
+
295
+ ```javascript
296
+ {
297
+ source_type: 'articles',
298
+ source_env: 'analytics', // optional, defaults to the engine owning env
299
+ handler: {
300
+ kind: 'function',
301
+ name: 'projectArticleChanges',
302
+ env: 'analytics', // optional, defaults to the engine owning env
303
+ },
304
+ mode: 'async',
305
+ bootstrap: 'log',
306
+ originMode: 'all',
307
+ batchSize: 64,
308
+ hydrateValues: true,
309
+ cursorKey: 'processor@article-projector',
310
+ lockMode: 'exclusive',
311
+ failOnHandlerError: true,
312
+ }
313
+ ```
314
+
315
+ Config notes:
316
+
317
+ - `source_type` — type whose change log the processor consumes
318
+ - `handler.kind` — currently must be `"function"`
319
+ - `handler.name` — function to invoke for each delivered batch of changes
320
+ - `source_env` — optional env name for the source type; defaults to the engine owning env
321
+ - `handler.env` — optional env name for the function registry; defaults to the engine owning env
322
+ - `mode`, `bootstrap`, `originMode`, `batchSize`, `hydrateValues`, `cursorKey`, `lockMode` — forwarded to the underlying processor runtime
323
+ - `failOnHandlerError` — included in runtime metadata; V1 engine behavior treats handler failures as engine errors
324
+
325
+ Behavior:
326
+
327
+ - consumes change-log batches through the normal processor feature
328
+ - invokes the configured env function with `ctx.payload` = `changes[]` (the batch array) and `ctx.processor` containing trigger metadata (`mode`, `sourceType`, `sourceEnv`, `processor`, `engineKey`, `cursorKey`)
329
+ - exposes processor cursor / progress / lag / error state through the engine runtime API
330
+ - can read from one env's type log while resolving the handler function from another env
331
+
332
+ Runtime stats exposed through `engine.api.stats()` / `engine.api.status()` include:
333
+
334
+ - `source_type`
335
+ - resolved `source_env`
336
+ - resolved handler metadata
337
+ - `state`
338
+ - `lastClock`
339
+ - `headClock`
340
+ - `lag`
341
+ - `progress`
342
+ - `processedChanges`
343
+ - `failedBatches`
344
+
345
+ Minimal pipeline membership example:
346
+
347
+ ```javascript
348
+ await analytics.pipelines.create({
349
+ name: 'projection-pipeline',
350
+ template: null,
351
+ status: 'active',
352
+ meta: { label: 'Projection pipeline' },
353
+ engines: [{ type: 'processor', name: 'article-projector', role: 'processor' }],
354
+ });
355
+ ```
356
+
357
+ ### `materializer` engine
358
+
359
+ Step 10 adds a `materializer` engine type for deterministic source→target collection projection.
360
+
361
+ Unlike the generic `processor`, a materializer has an **explicit target type** and a **return-ops contract** that enables safe rebuild.
362
+
363
+ Key differences from `processor`:
364
+
365
+ | Concern | `processor` | `materializer` |
366
+ | ----------------- | ----------------------- | ------------------------------------- |
367
+ | Target | implicit (side effects) | explicit (declared in config) |
368
+ | Rebuild | not safely possible | first-class `rebuild()` operation |
369
+ | Function contract | writes via `ctx.env` | returns ops array for engine to apply |
370
+ | Target ownership | unknown | engine owns the target lifecycle |
371
+
372
+ Typical flow:
373
+
374
+ ```javascript
375
+ const analytics = await db.createEnvironment('analytics');
376
+ await analytics.registerType('orders');
377
+
378
+ await analytics.functions.create({
379
+ name: 'projectOrders',
380
+ source: `async (ctx) => {
381
+ // ctx.payload = changes[]
382
+ // ctx.materializer = { sourceType, targetType, sourceEnv, targetEnv, mode, ... }
383
+ const ops = [];
384
+ for (const change of ctx.payload) {
385
+ if (change.action === 'put') {
386
+ ops.push({
387
+ action: 'put',
388
+ key: change.key,
389
+ value: { total: change.value.total, customerId: change.value.customerId },
390
+ });
391
+ }
392
+ if (change.action === 'remove') {
393
+ ops.push({ action: 'remove', key: change.key });
394
+ }
395
+ }
396
+ return ops; // engine applies these to target_type
397
+ }`,
398
+ });
399
+
400
+ const engine = await analytics.engines.createAndStartEngine('materializer', 'order-summary', {
401
+ source_type: 'orders',
402
+ target_type: 'order_summaries',
403
+ handler: { kind: 'function', name: 'projectOrders' },
404
+ bootstrap: 'snapshot',
405
+ batchSize: 128,
406
+ });
407
+
408
+ await analytics.put('orders', 'o1', { total: 99.5, customerId: 'c1' });
409
+ // → order_summaries/o1 is written automatically by the engine
410
+
411
+ // Re-materialize from scratch:
412
+ await engine.api.rebuild();
413
+ ```
414
+
415
+ `materializer` config shape:
416
+
417
+ ```javascript
418
+ {
419
+ source_type: 'orders',
420
+ target_type: 'order_summaries',
421
+ source_env: 'analytics', // optional, defaults to engine env
422
+ target_env: 'analytics', // optional, defaults to engine env
423
+ bootstrap: 'snapshot', // 'snapshot' | 'log'
424
+ originMode: 'all',
425
+ batchSize: 128,
426
+ clearTargetOnRebuild: true, // whether rebuild truncates target first
427
+ handler: {
428
+ kind: 'function',
429
+ name: 'projectOrders',
430
+ env: 'analytics', // optional, defaults to engine env
431
+ recordRuns: 'errors',
432
+ },
433
+ }
434
+ ```
435
+
436
+ Config notes:
437
+
438
+ - `source_type` — type whose change log the materializer consumes
439
+ - `target_type` — type the engine writes to (created automatically if absent)
440
+ - `handler.kind` — currently must be `"function"`
441
+ - `handler.name` — function invoked for each batch; must return an ops array
442
+ - `source_env` / `target_env` — optional env overrides
443
+ - `clearTargetOnRebuild` — whether `rebuild()` truncates the target before replaying (default: `true`)
444
+ - `bootstrap`, `originMode`, `batchSize` — forwarded to the underlying processor runtime
445
+
446
+ Function contract:
447
+
448
+ - **`ctx.payload`** = `changes[]` — batch of change records
449
+ - `change.action` = `'put' | 'remove'`
450
+ - `change.key` = source key
451
+ - `change.value` = hydrated source document for puts
452
+ - `change.clock` = live log clock, or `null` during snapshot bootstrap
453
+ - **`ctx.materializer`** = trigger metadata (`sourceType`, `targetType`, `sourceEnv`, `targetEnv`, `mode`, `engineKey`, `cursorKey`)
454
+ - **Return value** = `ops[]` — array of `{ action: 'put'|'remove', key, value? }` objects
455
+ - The function must **not** write directly via `ctx.env` — the engine applies the returned ops
456
+
457
+ `ctx.materializer.mode` is:
458
+
459
+ - `'build'` during bootstrap / replay
460
+ - `'live'` during normal ongoing consumption
461
+
462
+ Engine API:
463
+
464
+ - `engine.api.stats()` / `engine.api.status()` — state, lag, processedChanges, appliedOps, targetCount
465
+ - `engine.api.rebuild()` — stop, clear target (if configured), reset cursor, replay from origin
466
+ - `engine.api.resetCursor()` — reset cursor only without clearing target
467
+ - `engine.api.pause()` / `engine.api.resume()` — pause/resume consumption
468
+ - `engine.api.retry()` — retry after error state
469
+
470
+ ```javascript
471
+ const all = await okdb.pipelines.list();
472
+ const analyticsOnly = await okdb.pipelines.list({ envName: 'analytics' });
473
+ const record = await okdb.pipelines.get('analytics', 'articles-ingest');
474
+ ```
475
+
476
+ ---
477
+
478
+ ## Lifecycle behavior in V1
479
+
480
+ The base feature is intentionally narrow.
481
+
482
+ Allowed updates:
483
+
484
+ - `status`
485
+ - `meta`
486
+
487
+ Supported lifecycle operations:
488
+
489
+ - `create`
490
+ - `get`
491
+ - `list`
492
+ - `update` (`meta` / `status` only)
493
+ - `start`
494
+ - `stop`
495
+ - `remove`
496
+
497
+ Topology is structurally immutable in V1:
498
+
499
+ - changing engine membership is rejected
500
+ - changing engine roles is rejected
501
+ - changing engine order is rejected
502
+
503
+ ### Aggregate health
504
+
505
+ Aggregate health is derived at runtime from persisted pipeline `status` and current member engine state:
506
+
507
+ - pipeline `status === 'stopped'` → health `stopped`
508
+ - all members online → health `online`
509
+ - no members online and all are `error` / `stopped` / `missing` → health `error`
510
+ - otherwise → health `degraded`
511
+
512
+ ### Safe delete behavior
513
+
514
+ `remove()` deletes the pipeline record and uninstalls engines owned by the same env.
515
+
516
+ Shared/global engines are preserved.
517
+
518
+ ### HTTP routes
519
+
520
+ Generic pipelines now expose env-scoped routes:
521
+
522
+ - `GET /api/env/:env/pipelines`
523
+ - `GET /api/env/:env/pipelines/:pipeline`
524
+ - `POST /api/env/:env/pipelines`
525
+ - `POST /api/env/:env/pipelines/:pipeline/start`
526
+ - `POST /api/env/:env/pipelines/:pipeline/stop`
527
+ - `DELETE /api/env/:env/pipelines/:pipeline`
528
+
529
+ Read responses include derived pipeline/member inspection data such as:
530
+
531
+ - pipeline `health`
532
+ - ordered member `engines`
533
+ - per-member `role`, `type`, `name`
534
+ - per-member `state`, `status`, `isRunning`, `owned`, `storeEnv`
535
+ - engine `key`, `config`, and `meta` when the referenced engine exists
536
+ - runtime cursor / lag / progress / error fields when the member exposes them
537
+
538
+ ### Admin visibility
539
+
540
+ The admin UI now exposes pipelines and engines through three complementary views:
541
+
542
+ - **Queue → Workers** — create and manage `queue-worker` engines directly for the selected job type
543
+ - **DB → Type detail** — open a type-scoped engines view for embeddings/vector pipelines, including shortcuts from the vector/index drill-ins back to the owning pipeline
544
+ - **Engines** — the primary env-scoped workspace for cross-type inspection, with filters for mode, pipeline family, engine type, status, search text, and source type
545
+
546
+ Current behavior:
547
+
548
+ - all engine CRUD and inspection still resolves through env-scoped APIs such as `/api/env/:env/engines`
549
+ - type-local pipeline views stay constrained to the selected env + source type
550
+ - embedding indexer/search panels can jump back to the owning pipeline record
551
+ - queue-worker creation is already direct from the Queue section
552
+ - type-scoped DB views now open the same shared create wizard in a modal, with the env + source type pre-scoped and the source type locked to the current DB context
553
+ - that type-scoped modal supports `processor`, `materializer`, and `embedding`; `queue-worker` creation stays direct from the Queue section
554
+ - the global Engines create flow still supports `processor`, `materializer`, `queue-worker`, and `embedding` from one place
555
+
556
+ ### Sync / runtime activation
557
+
558
+ Synced pipeline declarations now reconcile through the same higher-level runtime activation seam used for synced engines.
559
+
560
+ That shared activation path runs:
561
+
562
+ - after `OKDB.open()` startup restore
563
+ - after each sync reconcile pass completes
564
+
565
+ Behavior in V1:
566
+
567
+ - env-scoped engine records still restore/start through the engine feature
568
+ - pipeline records add a second reconciliation pass based on persisted pipeline `status`
569
+ - `status: 'active'` attempts to bring all present members online in declaration order
570
+ - `status: 'stopped'` ensures running members are stopped in reverse order
571
+ - if a synced pipeline arrives before all referenced engine records exist locally, activation is skipped for that pass and retried on the next shared runtime activation cycle
572
+ - per-pipeline activation failures are logged and retried later; they do not abort the broader reconcile pass
573
+
574
+ Cluster expectation:
575
+
576
+ - sync replicates declarations (`~engines`, `~pipelines`, env records)
577
+ - local nodes then reconcile those declarations into runtime state
578
+ - structural completeness is still required for a pipeline to become fully active
579
+
580
+ ---
581
+
582
+ ## Relation to embeddings
583
+
584
+ Embeddings now use this generic pipeline model as their persisted grouping layer while keeping the richer `okdb.embeddings` facade.
585
+
586
+ Current behavior:
587
+
588
+ - `okdb.embeddings.createPipeline(...)` provisions the underlying engines **and** persists an env-local `~pipelines` record
589
+ - that record uses the pipeline `storage_key` as its generic name
590
+ - member roles are explicit and ordered: `embedder`, `indexer`, optional `worker`, `search`
591
+ - the record is tagged with `meta.family = 'embeddings'` so specialized embeddings views can recognize it cleanly
592
+ - embeddings lifecycle routes now delegate to the generic pipeline feature when a generic record exists
593
+
594
+ Embeddings-backed records also use `meta.lifecycleSkipRoles = ['embedder']`.
595
+
596
+ That keeps shared embedders out of per-pipeline stop/start behavior while still allowing generic pipeline operations to manage env-owned members such as the indexer, search engine, and optional queue worker.
597
+
598
+ This makes embeddings the first built-in feature validated on top of the generic pipeline record model rather than only name-based engine grouping.