okengine 0.10.1 → 0.10.3

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 (141) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/site/content/docs/ai/mcp.mdx +0 -1
  4. package/site/content/docs/elements/ai.mdx +0 -6
  5. package/site/content/docs/elements/channel.mdx +0 -6
  6. package/site/content/docs/elements/clock.mdx +2 -8
  7. package/site/content/docs/elements/flow.mdx +10 -17
  8. package/site/content/docs/elements/gate.mdx +4 -10
  9. package/site/content/docs/elements/signal.mdx +4 -13
  10. package/site/content/docs/elements/store.mdx +9 -16
  11. package/site/content/docs/elements/vault.mdx +1 -7
  12. package/site/content/docs/get-started/basic-usage.mdx +1 -9
  13. package/site/content/docs/get-started/introduction.mdx +1 -1
  14. package/site/content/docs/get-started/why.mdx +1 -2
  15. package/site/content/docs/index.mdx +0 -1
  16. package/site/content/docs/meta.json +0 -1
  17. package/site/content/docs/reference/cli.md +12 -12
  18. package/site/content/docs/reference/fx.mdx +6 -7
  19. package/src/auth/auth.test.ts +1 -2
  20. package/src/auth/bindings.ts +5 -15
  21. package/src/auth/gate-auth.test.ts +2 -2
  22. package/src/cli/ai-setup/ai-setup.test.ts +3 -1
  23. package/src/cli/ai-setup/apply.ts +13 -0
  24. package/src/cli/build.test.ts +67 -0
  25. package/src/cli/build.ts +33 -0
  26. package/src/cli/db-seed.ts +1 -1
  27. package/src/cli/dev-controls.test.ts +43 -48
  28. package/src/cli/dev-controls.ts +23 -172
  29. package/src/cli/dev.test.ts +90 -5
  30. package/src/cli/dev.ts +39 -16
  31. package/src/cli/doctor.ts +98 -5
  32. package/src/cli/load-config.images.test.ts +31 -1
  33. package/src/cli/load-config.ts +2 -2
  34. package/src/cli/safe-defaults.test.ts +1 -1
  35. package/src/client/notes-contract.test.ts +3 -4
  36. package/src/compiler/aot.test.ts +1 -2
  37. package/src/compiler/extract.test.ts +76 -21
  38. package/src/compiler/extract.ts +15 -3
  39. package/src/compiler/fixtures/raw/raw-unannotated.ts +2 -4
  40. package/src/compiler/fixtures/skyport/oke.config.ts +4 -2
  41. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +4 -8
  42. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -2
  43. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +1 -2
  44. package/src/compiler/fixtures/skyport.expected.json +3 -3
  45. package/src/compiler/fixtures/triggers/five-triggers.ts +5 -10
  46. package/src/compiler/generate-adopt.test.ts +85 -0
  47. package/src/compiler/generate-adopt.ts +111 -0
  48. package/src/config/driver-defaults.test.ts +122 -0
  49. package/src/config/driver-defaults.ts +186 -0
  50. package/src/config/index.ts +97 -7
  51. package/src/console/server/dry-run.audit.test.ts +2 -2
  52. package/src/console/server/flows.ts +50 -150
  53. package/src/docker/compose.ts +13 -3
  54. package/src/docker/images-config.test.ts +168 -0
  55. package/src/docker/recipes/llama-cpp.ts +10 -1
  56. package/src/docker/stack-id.ts +1 -0
  57. package/src/elements/channel/declare.ts +27 -1
  58. package/src/elements/clock/chaos-child.ts +3 -6
  59. package/src/elements/clock/chaos.test.ts +1 -2
  60. package/src/elements/clock.test.ts +2 -4
  61. package/src/elements/signal/declare.ts +25 -1
  62. package/src/elements/store/declare.ts +27 -1
  63. package/src/elements/store/resource.ts +6 -11
  64. package/src/elements/store/upsert-app.test.ts +1 -2
  65. package/src/elements/vault/declare.ts +29 -1
  66. package/src/kernel/adopt-barrel-fresh.test.ts +103 -0
  67. package/src/kernel/app.ts +66 -9
  68. package/src/kernel/auto-registry.test.ts +198 -0
  69. package/src/kernel/boot-bind/channel.ts +12 -4
  70. package/src/kernel/boot-bind/clock.ts +3 -3
  71. package/src/kernel/boot-bind/gate.ts +7 -4
  72. package/src/kernel/boot-bind/honor-config.test.ts +5 -5
  73. package/src/kernel/boot-bind/journal.ts +3 -3
  74. package/src/kernel/boot-bind/signal.ts +3 -1
  75. package/src/kernel/boot-bind/store.test.ts +19 -0
  76. package/src/kernel/boot-bind/store.ts +24 -9
  77. package/src/kernel/boot-bind/vault.ts +3 -3
  78. package/src/kernel/boot.test.ts +19 -15
  79. package/src/kernel/boot.ts +81 -1
  80. package/src/kernel/call.test.ts +5 -10
  81. package/src/kernel/compensate.test.ts +3 -6
  82. package/src/kernel/concurrency.test.ts +3 -5
  83. package/src/kernel/correlation.test.ts +4 -8
  84. package/src/kernel/edge.test.ts +1 -1
  85. package/src/kernel/effects-stamping.test.ts +4 -7
  86. package/src/kernel/element-registries.ts +27 -0
  87. package/src/kernel/errors.ts +11 -0
  88. package/src/kernel/flow.test.ts +8 -15
  89. package/src/kernel/flow.ts +12 -14
  90. package/src/kernel/hook-timing.test.ts +2 -2
  91. package/src/kernel/hooks.test.ts +5 -10
  92. package/src/kernel/horizontal-child.ts +5 -10
  93. package/src/kernel/journal-boot.test.ts +2 -4
  94. package/src/kernel/pipeline.test.ts +6 -12
  95. package/src/kernel/plugin/capabilities.test.ts +1 -1
  96. package/src/kernel/plugin/decorate.test.ts +3 -8
  97. package/src/kernel/plugin/scoping.test.ts +6 -16
  98. package/src/kernel/plugin-elements.test.ts +1 -1
  99. package/src/kernel/plugin-needs.test.ts +1 -1
  100. package/src/kernel/ready.test.ts +1 -2
  101. package/src/kernel/registry-isolation.test.ts +5 -5
  102. package/src/kernel/triggers.ts +1 -1
  103. package/src/plugins/anonymous.ts +1 -3
  104. package/src/plugins/compression.test.ts +6 -8
  105. package/src/plugins/config-source.test.ts +1 -1
  106. package/src/plugins/config-source.ts +1 -2
  107. package/src/plugins/cors.test.ts +10 -10
  108. package/src/plugins/csrf.test.ts +2 -2
  109. package/src/plugins/headers.test.ts +14 -15
  110. package/src/plugins/ip-allowlist.test.ts +9 -9
  111. package/src/plugins/magic-link.ts +2 -6
  112. package/src/plugins/maintenance-mode.test.ts +6 -6
  113. package/src/plugins/otp.ts +5 -15
  114. package/src/plugins/passkey.ts +4 -12
  115. package/src/plugins/two-factor.ts +3 -9
  116. package/src/plugins/username.ts +2 -6
  117. package/src/release/measure.ts +1 -1
  118. package/src/runs/runs.test.ts +3 -5
  119. package/src/runtime/serve.test.ts +2 -4
  120. package/src/test/create-test-app.test.ts +3 -7
  121. package/src/test/provisions.integration.test.ts +4 -9
  122. package/src/test/reset-element-registries.ts +31 -0
  123. package/site/content/docs/console/access.mdx +0 -29
  124. package/site/content/docs/console/ai.mdx +0 -35
  125. package/site/content/docs/console/architecture.mdx +0 -35
  126. package/site/content/docs/console/channels.mdx +0 -37
  127. package/site/content/docs/console/clock.mdx +0 -51
  128. package/site/content/docs/console/flows.mdx +0 -31
  129. package/site/content/docs/console/gates.mdx +0 -73
  130. package/site/content/docs/console/index.mdx +0 -54
  131. package/site/content/docs/console/manifest-diff.mdx +0 -34
  132. package/site/content/docs/console/meta.json +0 -24
  133. package/site/content/docs/console/overview.mdx +0 -40
  134. package/site/content/docs/console/plugins.mdx +0 -41
  135. package/site/content/docs/console/privacy.mdx +0 -32
  136. package/site/content/docs/console/runs.mdx +0 -50
  137. package/site/content/docs/console/signals.mdx +0 -40
  138. package/site/content/docs/console/store.mdx +0 -32
  139. package/site/content/docs/console/tenancy.mdx +0 -32
  140. package/site/content/docs/console/traces.mdx +0 -38
  141. package/site/content/docs/console/vault.mdx +0 -41
package/README.md CHANGED
@@ -74,7 +74,7 @@ import { z } from "zod";
74
74
 
75
75
  export const health = on(
76
76
  http.get("/health").gate(gate.public),
77
- flow({
77
+ flow("health.check", {
78
78
  out: z.object({ ok: z.literal(true) }),
79
79
  do: () => ({ ok: true as const }),
80
80
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okengine",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "One law. Eight elements. Ten exports. One package. One manifest. Every backend need is derived, never added.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -98,7 +98,6 @@ The docs content ships inside the `okengine` package, so the index your agent se
98
98
 
99
99
  ## Learn more
100
100
 
101
- - [Console · Access](/docs/console/access) — how operator tokens and grants work
102
101
  - [Agent contracts](/docs/ai/skills) — what agents are taught about the system they operate
103
102
  - [Flow](/docs/elements/flow) — the effects the MCP reads back
104
103
 
@@ -289,7 +289,6 @@ Bound it at declaration: `maxSteps` caps iterations, `budget.maxCostPerRun` caps
289
289
 
290
290
  - [Flow](/docs/elements/flow) — `fx.ask` and `fx.search` inside `do`
291
291
  - [Store](/docs/elements/store) — `store.index`, the home of embeddings
292
- - [Console · AI](/docs/console/ai) — prompts, versions, cost per run
293
292
 
294
293
  ## Next
295
294
 
@@ -304,9 +303,4 @@ Bound it at declaration: `maxSteps` caps iterations, `budget.maxCostPerRun` caps
304
303
  description="Eight elements overview."
305
304
  href="/docs/get-started/introduction"
306
305
  />
307
- <Card
308
- title="Console"
309
- description="Panels derived from the Manifest."
310
- href="/docs/console/overview"
311
- />
312
306
  </Cards>
@@ -326,7 +326,6 @@ Confirm a visible OS notification titled `okengine webpush interop`.
326
326
  ## Learn more
327
327
 
328
328
  - [Flow](/docs/elements/flow) — `fx.send` inside `do`
329
- - [Console · Channels](/docs/console/channels) — receipts, attempts, suppression
330
329
  - [Environment Variables](/docs/reference/environment-variables) — Channel boot credentials
331
330
  - [Configuration](/docs/reference/configuration) — `drivers.channel.*` maps
332
331
  - [i18n](/docs/reference/i18n) — ICU / `fx.t` vs Channel `{{field}}` catalogs
@@ -341,9 +340,4 @@ Confirm a visible OS notification titled `okengine webpush interop`.
341
340
  description="Eight elements overview."
342
341
  href="/docs/get-started/introduction"
343
342
  />
344
- <Card
345
- title="Console"
346
- description="Panels derived from the Manifest."
347
- href="/docs/console/overview"
348
- />
349
343
  </Cards>
@@ -26,7 +26,7 @@ import { on, flow, every } from "okengine";
26
26
 
27
27
  export const purgeOld = on(
28
28
  every("1h"),
29
- flow({
29
+ flow("links.purgeOld", {
30
30
  do: async (_, fx) => {
31
31
  const cutoff = fx.clock.now() - 30 * 24 * 60 * 60 * 1000; // 30 days
32
32
  await fx.store(db).delete(links).where(lt(links.createdAt, cutoff));
@@ -55,7 +55,7 @@ export const dailyReport = clock("daily-report", {
55
55
  ```typescript title="src/flows/reports/daily.ts"
56
56
  export const sendDaily = on(
57
57
  dailyReport,
58
- flow({
58
+ flow("reports.sendDaily", {
59
59
  do: async (_, fx) => {
60
60
  /* … */
61
61
  },
@@ -195,7 +195,6 @@ They are not sharing one CronStore. In-memory leases are per process. Point ever
195
195
 
196
196
  - [Flow](/docs/elements/flow) — `on(trigger, flow)` and the `fx` surface
197
197
  - [fx · Runs](/docs/reference/fx#runs-observability-read) — native SLO checkers via `on(every(…))` + `fx.runs`
198
- - [Console · Clock](/docs/console/clock) — health numbers, pause / edit / wake early
199
198
  - [Signal](/docs/elements/signal) — reacting to events instead of time
200
199
 
201
200
  ## Next
@@ -207,9 +206,4 @@ They are not sharing one CronStore. In-memory leases are per process. Point ever
207
206
  description="Eight elements overview."
208
207
  href="/docs/get-started/introduction"
209
208
  />
210
- <Card
211
- title="Console"
212
- description="Panels derived from the Manifest."
213
- href="/docs/console/overview"
214
- />
215
209
  </Cards>
@@ -28,7 +28,7 @@ import { z } from "zod";
28
28
 
29
29
  export const createOrder = on(
30
30
  http.post("/orders"),
31
- flow({
31
+ flow("orders.create", {
32
32
  in: z.object({ sku: z.string(), qty: z.number().int().min(1) }),
33
33
  out: z.object({ id: z.string() }),
34
34
  errors: { OutOfStock: z.object({ left: z.number() }) },
@@ -106,7 +106,7 @@ Built-in codes attach a localized `message` ([Errors](/docs/reference/errors));
106
106
  ```typescript
107
107
  export const findOrder = on(
108
108
  http.get("/orders/:id").gate(member), // gates evaluate before do runs
109
- flow({
109
+ flow("orders.find", {
110
110
  in: z.object({ id: z.string() }),
111
111
  out: Order,
112
112
  errors: { NotFound: z.object({}) },
@@ -124,7 +124,7 @@ await fx.emit(orderPlaced, { orderId: id }); // inside the producing flow
124
124
 
125
125
  on(
126
126
  orderPlaced,
127
- flow({
127
+ flow("orders.sendReceipt", {
128
128
  do: async ({ orderId }, fx) => {
129
129
  /* … */
130
130
  },
@@ -139,7 +139,7 @@ on(
139
139
  ```typescript
140
140
  on(
141
141
  every("1h"),
142
- flow({
142
+ flow("sessions.sweepExpired", {
143
143
  do: async (_, fx) => {
144
144
  const cutoff = fx.clock.now() - 30 * 24 * 60 * 60 * 1000;
145
145
  await fx.store(db).delete(sessions).where(lt(sessions.createdAt, cutoff));
@@ -155,7 +155,7 @@ CDC is built in; the flow receives `{ before, after }`:
155
155
  ```typescript
156
156
  on(
157
157
  db.table(orders).changed("status"),
158
- flow({
158
+ flow("orders.reverify", {
159
159
  do: ({ before, after }, fx) => fx.log.info("status", { from: before.status, to: after.status }),
160
160
  }),
161
161
  );
@@ -166,7 +166,7 @@ on(
166
166
  Drop `on()` and it is still a real Flow — contracts, Manifest entry, everything. Other flows call it through `fx.call`:
167
167
 
168
168
  ```typescript
169
- export const getOrder = flow({
169
+ export const getOrder = flow("orders.get", {
170
170
  in: OrderRef,
171
171
  out: Order,
172
172
  do: async ({ id }, fx) => {
@@ -211,7 +211,7 @@ Everything a flow may touch, on one object:
211
211
  Set `durable: true` and every `fx` call is journaled. Wrap side effects in `fx.step` and they never re-run on replay:
212
212
 
213
213
  ```typescript
214
- export const chargeOrder = flow({
214
+ export const chargeOrder = flow("payments.chargeOrder", {
215
215
  durable: true, // every fx call below is journaled
216
216
  in: OrderRef,
217
217
  out: z.boolean(),
@@ -233,14 +233,14 @@ export const chargeOrder = flow({
233
233
 
234
234
  Replay is **at-least-once** for a step whose body never persisted (crash mid-step, lease overrun): that step re-runs on reclaim, so keep step bodies short or internally idempotent. A client transport retry starts a _new_ run with a fresh `runId` — request-level idempotency is an application concern, not the journal's.
235
235
 
236
- For flaky sub-steps, wrap the work in `fx.retry` **inside** `fx.step` so a completed charge is never retried on resume. Coarse whole-body retry is also available as `flow({ retry: { retries, delay, backoff, jitter } })` and reuses the same journal session.
236
+ For flaky sub-steps, wrap the work in `fx.retry` **inside** `fx.step` so a completed charge is never retried on resume. Coarse whole-body retry is also available as `flow(name, { retry: { retries, delay, backoff, jitter } })` and reuses the same journal session.
237
237
 
238
238
  After a **terminal** failure (`fx.fail` or exhausted retries / uncaught throw), optional
239
239
  `compensate` runs under the same journal. Undo work must use **new** step names
240
240
  (`undo:…`) — never rewind forward steps:
241
241
 
242
242
  ```typescript
243
- export const chargeOrder = flow({
243
+ export const chargeOrder = flow("payments.chargeOrder", {
244
244
  durable: true,
245
245
  in: OrderRef,
246
246
  out: z.boolean(),
@@ -295,7 +295,7 @@ Use `fx.all` (or `fx.race`) with thunks. The first rejection aborts siblings thr
295
295
  </Accordion>
296
296
  <Accordion title="Durable flow retried a completed charge">
297
297
 
298
- Put `fx.retry` **inside** `fx.step`, not around it. Completed steps replay from the journal and never re-run. `flow({ retry })` is for coarse whole-body retries on the same session.
298
+ Put `fx.retry` **inside** `fx.step`, not around it. Completed steps replay from the journal and never re-run. `flow(name, { retry })` is for coarse whole-body retries on the same session.
299
299
 
300
300
  </Accordion>
301
301
  <Accordion title="When does compensate run?">
@@ -320,8 +320,6 @@ Only that run fails — the schedule keeps firing and the process does not exit.
320
320
  - [fx](/docs/reference/fx) — full `fx` surface, including ICU `fx.t` / `fx.locale`
321
321
  - [Signal](/docs/elements/signal) — delivery physics (`once` · `broadcast` · `live`)
322
322
  - [Clock](/docs/elements/clock) — schedules and durable sleep
323
- - [Console · Flows](/docs/console/flows) — the Manifest-derived panel
324
- - [Runs](/docs/console/runs) — how a flow execution is observed
325
323
 
326
324
  ## Next
327
325
 
@@ -332,9 +330,4 @@ Only that run fails — the schedule keeps firing and the process does not exit.
332
330
  description="Eight elements overview."
333
331
  href="/docs/get-started/introduction"
334
332
  />
335
- <Card
336
- title="Console"
337
- description="Panels derived from the Manifest."
338
- href="/docs/console/overview"
339
- />
340
333
  </Cards>
@@ -66,7 +66,7 @@ import { member, canBook, fair } from "../../gates";
66
66
 
67
67
  export const health = on(
68
68
  http.get("/health").gate(gate.public),
69
- flow({
69
+ flow("health.check", {
70
70
  out: HealthOut,
71
71
  do: () => ({ ok: true as const }),
72
72
  }),
@@ -74,7 +74,7 @@ export const health = on(
74
74
 
75
75
  export const shorten = on(
76
76
  http.post("/links").gate(member, canBook, fair),
77
- flow({
77
+ flow("links.shorten", {
78
78
  in: NewLink,
79
79
  out: LinkCode,
80
80
  errors: { Taken },
@@ -174,8 +174,8 @@ Every HTTP trigger must carry a gate or `gate.public`. Omitting both fails boot
174
174
  `GateBootError` — message starts with `gate boot failed —` and lists every gap.
175
175
 
176
176
  ```typescript
177
- on(http.get("/health").gate(gate.public), flow({/* … */}));
178
- on(http.post("/bookings").gate(member, canBook), flow({/* … */}));
177
+ on(http.get("/health").gate(gate.public), flow("health.check", {/* … */}));
178
+ on(http.post("/bookings").gate(member, canBook), flow("bookings.create", {/* … */}));
179
179
  ```
180
180
 
181
181
  **Consequence:** first `fetch` / `execute` auto-boots (`autoBoot` defaults to `true`).
@@ -308,7 +308,6 @@ Keying an authenticated endpoint by IP punishes shared NAT.
308
308
  - [fx](/docs/reference/fx) — `fx.auth`, `fx.operator`, `fx.principal`
309
309
  - [Client](/docs/reference/client) — Bearer `createClient` + `okengine/client/auth`
310
310
  - [Plugins](/docs/plugins) — username, magic link, OTP, TOTP, passkeys
311
- - [Console · Gates](/docs/console/gates) — decision audit and posture
312
311
  - [Vault](/docs/elements/vault) — credentials your policies protect
313
312
 
314
313
  ## Next
@@ -316,9 +315,4 @@ Keying an authenticated endpoint by IP punishes shared NAT.
316
315
  <Cards>
317
316
  <Card title="Vault" description="Continue to Vault." href="/docs/elements/vault" />
318
317
  <Card title="Plugins" description="Sign-in method plugins under /auth." href="/docs/plugins" />
319
- <Card
320
- title="Console"
321
- description="Panels derived from the Manifest."
322
- href="/docs/console/overview"
323
- />
324
318
  </Cards>
@@ -58,7 +58,7 @@ A signal is a trigger like any other — the consumer is an ordinary Flow:
58
58
  ```typescript title="src/flows/orders/send-confirmation.ts"
59
59
  export const sendConfirmation = on(
60
60
  orderPlaced,
61
- flow({
61
+ flow("orders.sendConfirmation", {
62
62
  in: z.object({ orderId: z.string(), total: z.number() }),
63
63
  do: async (input, fx) => {
64
64
  await fx.send(orderConfirmed, { to: "user-1", data: input });
@@ -131,8 +131,7 @@ export const orderStatus = signal("order-status", {
131
131
  ```typescript title="src/flows/fulfillment/on-order.ts"
132
132
  on(
133
133
  orderPlaced,
134
- flow({
135
- name: "fulfillment.onOrder",
134
+ flow("fulfillment.onOrder", {
136
135
  do: async ({ orderId }, fx) => {
137
136
  await fx.emit(orderChanged, { orderId, kind: "placed" });
138
137
  await fx.emit(orderStatus, { orderId, status: "fulfilling" });
@@ -147,8 +146,7 @@ on(
147
146
  ```typescript title="src/flows/orders/side-effects.ts"
148
147
  on(
149
148
  orderChanged,
150
- flow({
151
- name: "cache.onOrderChanged",
149
+ flow("cache.onOrderChanged", {
152
150
  do: async ({ orderId }, fx) => {
153
151
  /* invalidate order:{orderId} */
154
152
  },
@@ -157,8 +155,7 @@ on(
157
155
 
158
156
  on(
159
157
  orderChanged,
160
- flow({
161
- name: "notify.onOrderChanged",
158
+ flow("notify.onOrderChanged", {
162
159
  do: async ({ orderId }, fx) => {
163
160
  await fx.send(orderConfirmed, { to: "user-1", data: { orderId } });
164
161
  },
@@ -294,7 +291,6 @@ At-least-once: crash-after-claim reclaims when the lease expires, and a handler
294
291
  ## Learn more
295
292
 
296
293
  - [Flow](/docs/elements/flow) — `on(trigger, flow)` and `fx.emit`
297
- - [Console · Signals](/docs/console/signals) — topology, delivery stats, DLQ replay
298
294
  - [Clock](/docs/elements/clock) — scheduled and delayed work
299
295
 
300
296
  ## Next
@@ -306,9 +302,4 @@ At-least-once: crash-after-claim reclaims when the lease expires, and a handler
306
302
  description="Eight elements overview."
307
303
  href="/docs/get-started/introduction"
308
304
  />
309
- <Card
310
- title="Console"
311
- description="Panels derived from the Manifest."
312
- href="/docs/console/overview"
313
- />
314
305
  </Cards>
@@ -80,7 +80,7 @@ All data access goes through `fx.store(db)` — a typed session, one table at a
80
80
  ```typescript title="src/flows/notes/create.ts"
81
81
  export const createNote = on(
82
82
  http.post("/notes"),
83
- flow({
83
+ flow("notes.create", {
84
84
  in: z.object({ title: z.string(), body: z.string() }),
85
85
  out: z.object({ id: z.string() }),
86
86
  do: async (input, fx) => {
@@ -490,9 +490,8 @@ await fx.store(sessions).set(`sess:${token}`, { userId }, "7d");
490
490
  const keys = await fx.store(sessions).list("sess:");
491
491
  ```
492
492
 
493
- **Consequence:** `list` is how the [Console · Store](/docs/console/store) browser enumerates a
494
- namespace. Prefer stable key prefixes (`user:`, `sess:`) so both your Flows and the Console stay
495
- readable.
493
+ **Consequence:** `list` enumerates a namespace. Prefer stable key prefixes (`user:`, `sess:`) so
494
+ your Flows and operator tools stay readable.
496
495
 
497
496
  ### Per-environment KV drivers
498
497
 
@@ -637,9 +636,9 @@ images: {
637
636
 
638
637
  **Known limit:** `fs` is single-host. Under horizontal scale each replica sees its own filesystem (silently inconsistent object views). Boot prints a one-shot warning when `drivers.store.files` is `fs`. Use `s3` for docker/prod (create-oke templates already do).
639
638
 
640
- <Callout title="Console can browse, not edit bytes">
641
- The [Console · Store](/docs/console/store) lists keys and can delete them. Direct edit is **KV +
642
- SQL only** — blob bodies are not patched from the Console.
639
+ <Callout title="Operator tools can browse, not edit bytes">
640
+ Operator tools can list keys and delete them. Direct edit is **KV + SQL only** — blob bodies are
641
+ not patched.
643
642
  </Callout>
644
643
 
645
644
  ### Images — `image` / `putImage`
@@ -861,9 +860,9 @@ Container images come from the `images` map — change the vendor by changing th
861
860
 
862
861
  Columns tagged `.pii()` or `.sensitive()` are masked at the store boundary — flows, logs, and the Console see a mask, not the value. Revealing cleartext PII requires an explicit `pii:reveal` gate on the flow, so access is a permission, not a convention.
863
862
 
864
- Optional `description` on a store (and `.describe("…")` on fields) becomes the human title in the
865
- [Console · Store](/docs/console/store) browser. Single-table `reads` / `writes` in the Manifest
866
- power cache invalidation and that same PII masking — see the Callout under [Querying by hand](#querying-by-hand).
863
+ Optional `description` on a store (and `.describe("…")` on fields) becomes its human title in
864
+ operator tools. Single-table `reads` / `writes` in the Manifest power cache invalidation and that
865
+ same PII masking — see the Callout under [Querying by hand](#querying-by-hand).
867
866
 
868
867
  ## Troubleshooting
869
868
 
@@ -915,7 +914,6 @@ Unlike KV/Files, unset `drivers.store.index` does **not** promote to `pgvector`
915
914
  - [Flow](/docs/elements/flow) — the `fx.store` session inside `do`
916
915
  - [AI](/docs/elements/ai) — `ai.embed` into a vector `store.index`, searched via `fx.search`
917
916
  - [Gate](/docs/elements/gate) — `pii:reveal` and other permissions on flows
918
- - [Console · Store](/docs/console/store) — browse data, cache keys, PII masking
919
917
  - [CLI Reference](/docs/reference/cli) — `oke db push` · `generate` · `migrate`
920
918
  - [Configuration](/docs/reference/configuration) — `drivers.store` maps and `images` pins
921
919
  - [Environment variables](/docs/reference/environment-variables) — Redis · S3 · meilisearch URLs
@@ -929,9 +927,4 @@ Unlike KV/Files, unset `drivers.store.index` does **not** promote to `pgvector`
929
927
  description="Eight elements overview."
930
928
  href="/docs/get-started/introduction"
931
929
  />
932
- <Card
933
- title="Console"
934
- description="Panels derived from the Manifest."
935
- href="/docs/console/overview"
936
- />
937
930
  </Cards>
@@ -62,7 +62,7 @@ Call `.reveal()` once at the boundary that needs the real credential:
62
62
  ```typescript title="src/flows/billing/charge.ts"
63
63
  export const charge = on(
64
64
  http.post("/charge"),
65
- flow({
65
+ flow("billing.charge", {
66
66
  in: ChargeInput,
67
67
  out: z.object({ id: z.string() }),
68
68
  do: async (input, fx) => {
@@ -251,7 +251,6 @@ Set the new value (`oke vault set` or the Console). The Console's rotation view
251
251
 
252
252
  ## Learn more
253
253
 
254
- - [Console · Vault](/docs/console/vault) — fingerprints, resolution chain, rotation blast radius
255
254
  - [Flow](/docs/elements/flow) — how `fx.vault` reads secrets inside `do`
256
255
  - [CLI Reference](/docs/reference/cli) — `oke vault set` · `list` · `import`
257
256
 
@@ -264,9 +263,4 @@ Set the new value (`oke vault set` or the Console). The Console's rotation view
264
263
  description="Eight elements overview."
265
264
  href="/docs/get-started/introduction"
266
265
  />
267
- <Card
268
- title="Console"
269
- description="Panels derived from the Manifest."
270
- href="/docs/console/overview"
271
- />
272
266
  </Cards>
@@ -44,9 +44,7 @@ import { z } from "zod";
44
44
 
45
45
  export const health = on(
46
46
  http.get("/health").gate(gate.public),
47
- flow({
48
- name: "main.health",
49
- unit: "main",
47
+ flow("main.health", {
50
48
  out: z.object({ ok: z.literal(true) }),
51
49
  do: () => ({ ok: true as const }),
52
50
  }),
@@ -148,7 +146,6 @@ bun test
148
146
  - [Flow](/docs/elements/flow) — triggers, contracts, effects, and composition
149
147
  - [Store](/docs/elements/store) — SQL, KV, files, index
150
148
  - [fx](/docs/reference/fx) — the full effect surface
151
- - [Console · Overview](/docs/console/overview) — Manifest-derived panels
152
149
 
153
150
  ## Next
154
151
 
@@ -163,9 +160,4 @@ bun test
163
160
  description="SQL, KV, files, index, and declarative resources."
164
161
  href="/docs/elements/store"
165
162
  />
166
- <Card
167
- title="Console"
168
- description="Manifest-derived flows, effects, traces, and architecture."
169
- href="/docs/console/overview"
170
- />
171
163
  </Cards>
@@ -29,7 +29,7 @@ import { z } from "zod";
29
29
 
30
30
  export const health = on(
31
31
  http.get("/health"),
32
- flow({
32
+ flow("health.check", {
33
33
  out: z.object({ ok: z.literal(true) }),
34
34
  do: () => ({ ok: true as const }),
35
35
  }),
@@ -49,7 +49,7 @@ shared lifecycle, optional live DB config, nothing to re-copy.
49
49
  Your observability stack learned your routes from sampled traffic. The Flow
50
50
  you deployed an hour ago is invisible until someone wires it by hand.
51
51
 
52
- **OKE derives:** the [Console](/docs/console/overview) reads the Manifest —
52
+ **OKE derives:** its operator interface reads the Manifest —
53
53
  flows, effects, traces, architecture — current on every save, in dev and prod
54
54
  (`:6533`).
55
55
 
@@ -118,7 +118,6 @@ ninth element — the set of eight is closed.
118
118
  - [Flow](/docs/elements/flow) — how effects are recorded and inferred
119
119
  - [Vault](/docs/elements/vault) — fail-loud secret contracts
120
120
  - [Plugins](/docs/reference/plugins) — the official HTTP glue set
121
- - [Console · Overview](/docs/console/overview) — the Manifest-derived operator UI
122
121
 
123
122
  ## Next
124
123
 
@@ -31,7 +31,6 @@ on(orderPlaced, sendReceipt);
31
31
  description="Official extensions — security, ops, performance."
32
32
  href="/docs/plugins"
33
33
  />
34
- <Card title="Console" description="Manifest-derived operator panels." href="/docs/console" />
35
34
  <Card
36
35
  title="Deployment"
37
36
  description="Compose, Swarm, Kubernetes, reverse proxy."
@@ -6,7 +6,6 @@
6
6
  "get-started",
7
7
  "elements",
8
8
  "plugins",
9
- "console",
10
9
  "deployment",
11
10
  "recipes",
12
11
  "providers",
@@ -67,18 +67,18 @@ so ● updates live if you stop a container; AI ● tracks model phase while the
67
67
  AI container is up. Boot does not wait for the model to become ready.
68
68
 
69
69
  On a TTY with `-d`, keyboard controls stay active under Logs. Status ● for
70
- compose/AI live on the board **above** Logs (not as log lines). Press `c` to
71
- clear the log pane and reprint the latest board. `l` / `?` also refresh first
72
- so the services/help panel is not mixed into request logs.
73
-
74
- | Key | Action |
75
- | ---------------------------- | ----------------------------------- |
76
- | `?` | help |
77
- | `c` | refresh — clear logs, show latest ● |
78
- | `q` | quit `oke dev` |
79
- | `l` | list docker services |
80
- | `u` / `x` | compose up / stop (whole stack) |
81
- | `1`–`9` then `u` / `x` / `r` | start / stop / restart one service |
70
+ compose/AI live on the board **above** Logs (not as log lines) it already
71
+ lists every service, so refresh is enough to see the stack; there is no
72
+ separate services panel. Press `r` to clear the log pane and reprint the
73
+ latest board. `?` also refreshes first so the help panel is not mixed into
74
+ request logs.
75
+
76
+ | Key | Action |
77
+ | --------- | ----------------------------------- |
78
+ | `?` | help |
79
+ | `r` | refresh clear logs, show latest ● |
80
+ | `q` | quit `oke dev` |
81
+ | `u` / `x` | compose up / stop (whole stack) |
82
82
 
83
83
  Compose stays quiet unless it fails. Process-local boot notices print once under
84
84
  the hero (not once per process).
@@ -7,7 +7,7 @@ icon: "Braces"
7
7
  `fx` is the second argument of every `do` — the single door to the world. This page is the whole surface; each entry notes the **effect it records**, which is what feeds the Manifest, caching, and capability checks.
8
8
 
9
9
  ```typescript
10
- flow({
10
+ flow("orders.example", {
11
11
  do: async (input, fx) => {
12
12
  // everything below, on this one object
13
13
  },
@@ -51,8 +51,7 @@ Declare `effects: { reads: ["runs"] }`. Powers native SLO checkers (Clock + Chan
51
51
  ```typescript
52
52
  on(
53
53
  every("5m"),
54
- flow({
55
- name: "ops.slo-check",
54
+ flow("ops.slo-check", {
56
55
  effects: { reads: ["runs"], sends: ["slo-alert"] },
57
56
  do: async (_, fx) => {
58
57
  const breaches = await fx.runs.checkSlo(
@@ -133,7 +132,7 @@ const rows = await fx.using(
133
132
  );
134
133
  ```
135
134
 
136
- **Consequence:** put `fx.retry` inside `fx.step` on durable flows so a completed charge never re-runs on resume. Coarse whole-body retry is `flow({ retry: { … } })` on the same journal session.
135
+ **Consequence:** put `fx.retry` inside `fx.step` on durable flows so a completed charge never re-runs on resume. Coarse whole-body retry is `flow(name, { retry: { … } })` on the same journal session.
137
136
 
138
137
  ## Channel
139
138
 
@@ -260,9 +259,9 @@ must log who started the call chain.
260
259
  ## Not on `fx`
261
260
 
262
261
  <Callout title="No fx.metric">
263
- Investigated and declined. [Runs](/docs/console/runs) already own per-invocation observability as
264
- wide events. Native alerting is `fx.runs` + Clock + Channel — not a second counter/gauge API.
265
- Optional OTLP export for existing Grafana/Datadog stacks is additive and never required.
262
+ Investigated and declined. `fx.runs` already provides per-invocation observability as wide events.
263
+ Native alerting is `fx.runs` + Clock + Channel — not a second counter/gauge API. Optional OTLP
264
+ export for existing Grafana/Datadog stacks is additive and never required.
266
265
  </Callout>
267
266
 
268
267
  ## Learn more
@@ -177,8 +177,7 @@ describe("cross-plane compile error", () => {
177
177
  path: "src/flows/console/store.ts",
178
178
  flow: "console.store.query",
179
179
  source: `
180
- export const query = flow({
181
- name: "console.store.query",
180
+ export const query = flow("console.store.query", {
182
181
  plane: "operator",
183
182
  do: (_i, fx) => fx.auth.userId,
184
183
  });
@@ -205,9 +205,7 @@ export function createAuthHttpBindings(
205
205
 
206
206
  const base = config.basePath;
207
207
 
208
- const refresh = flow({
209
- name: "auth.refresh",
210
- unit: "auth",
208
+ const refresh = flow("auth.refresh", {
211
209
  plane: "user",
212
210
  in: RefreshIn,
213
211
  out: SessionTokensOut,
@@ -231,9 +229,7 @@ export function createAuthHttpBindings(
231
229
  },
232
230
  });
233
231
 
234
- const revoke = flow({
235
- name: "auth.revoke",
236
- unit: "auth",
232
+ const revoke = flow("auth.revoke", {
237
233
  plane: "user",
238
234
  in: RevokeIn,
239
235
  out: z.object({ ok: z.literal(true) }),
@@ -252,9 +248,7 @@ export function createAuthHttpBindings(
252
248
  },
253
249
  });
254
250
 
255
- const me = flow({
256
- name: "auth.me",
257
- unit: "auth",
251
+ const me = flow("auth.me", {
258
252
  plane: "user",
259
253
  out: MeOut,
260
254
  errors: { AuthFailed },
@@ -289,9 +283,7 @@ export function createAuthHttpBindings(
289
283
  ];
290
284
 
291
285
  if (config.emailAndPassword.enabled) {
292
- const signInEmail = flow({
293
- name: "auth.signInEmail",
294
- unit: "auth",
286
+ const signInEmail = flow("auth.signInEmail", {
295
287
  plane: "user",
296
288
  in: EmailPasswordIn,
297
289
  out: SessionTokensOut,
@@ -319,9 +311,7 @@ export function createAuthHttpBindings(
319
311
  },
320
312
  });
321
313
 
322
- const signUpEmail = flow({
323
- name: "auth.signUpEmail",
324
- unit: "auth",
314
+ const signUpEmail = flow("auth.signUpEmail", {
325
315
  plane: "user",
326
316
  in: EmailPasswordIn,
327
317
  out: SessionTokensOut,
@@ -136,7 +136,7 @@ describe("gate.auth — autoBoot / posture", () => {
136
136
  });
137
137
 
138
138
  test(".needs(auth) satisfied by gate.auth without .plug(auth())", async () => {
139
- on(http.get("/x").gate(AUTH_SESSION_GATE), flow({ name: "x", do: () => ({ ok: true }) }));
139
+ on(http.get("/x").gate(AUTH_SESSION_GATE), flow("x", { do: () => ({ ok: true }) }));
140
140
  const dependent = plugin("needs-auth", { version: "0.0.1" }).needs("auth");
141
141
  const app = oke({
142
142
  name: "needs-gate-auth",
@@ -309,7 +309,7 @@ describe("gate.auth — email Flows + security", () => {
309
309
  });
310
310
 
311
311
  test("missing gate on custom HTTP still GateBootError", async () => {
312
- on(http.get("/open"), flow({ name: "open", do: () => ({ ok: true }) }));
312
+ on(http.get("/open"), flow("open", { do: () => ({ ok: true }) }));
313
313
  const app = oke({
314
314
  name: "gap",
315
315
  env: "local",
@@ -117,7 +117,9 @@ export default defineConfig({
117
117
  },
118
118
  },
119
119
  images: {
120
- "store.sql": "postgres:18-alpine",
120
+ store: {
121
+ sql: "postgres:18-alpine",
122
+ },
121
123
  },
122
124
  });
123
125
  `,