0.19

Every published okengine release, newest first.

all series Β· 0.18

v0.19.9

πŸ› Fixed

Dev, Keel & create-oke

  • oke dev prompts for Vault boot gaps again when the app calls oke() at module load (Keel / OPENROUTER_API_KEY). The probe now reads app.$options.secrets β€” the same list boot uses β€” instead of the drained secretRegistry. A failed app-child boot exits immediately instead of waiting 30s under bun --hot.
  • Keel prepare on Windows uses a directory junction (absolute target) instead of a symlink that needs Developer Mode (EPERM / -4048). Scripts invoke the checkout CLI (bun ../../src/cli/index.ts) so PowerShell cannot pick a global oke that then fails with Cannot find package 'zod'.

v0.19.8

πŸ› Fixed

  • oke dev recovers when Postgres rejects oke after you delete and recreate the project folder at the same path. Compose volumes keep the first init password; a new .env.local does not. Dev now reuses ~/.oke/stacks/<id>.env and, on password authentication failed, resets that project's volumes once.

v0.19.7

πŸ› Fixed

  • create-oke no longer deletes a newly created project when you press Ctrl+C during bun install or bun run dev. That wipe often failed mid-tree on Windows (EBUSY) and left an empty or half-deleted folder. Cancel still removes an unfinished folder if you interrupt before scaffold finishes.

v0.19.6

πŸ› Fixed

  • Console on Windows served the "Shell assets not built" fallback at :6533 even when ui-next/dist was present. SPA lookup used file:// URL .pathname (/C:/…) instead of a filesystem path.

♻️ Changed

Docs

  • CLI troubleshooting covers Console "Shell assets not built" on Windows.

v0.19.5

♻️ Changed

Dev, Keel & create-oke

  • Starters run the CLI through bunx --bun oke (bun run dev / bun run test) so Windows PowerShell does not need a local oke on PATH. Next-steps, README, and AGENTS.md show bun run dev / bunx oke. Scaffolded .vscode/settings.json prepends node_modules/.bin in integrated terminals.

Docs

  • Try It and CLI Quick start use bun run dev. CLI troubleshooting covers Windows oke not found and Compose **OKE1020**.

πŸ› Fixed

Runtime

  • Manifest extract skips node_modules / .git as path segments after POSIX normalize, so Windows node_modules\… is not parsed. Scanning those trees threw during extract and Docker-first oke dev hard-failed **OKE1020** on main.health. Failed extract is now part of the OKE1020 cause (not only a suppressible oke boot: warn). oke dev writes the parent Manifest to a temp file and the app child boots with it (OKE_MANIFEST_PATH).
  • src/flows/generated.ts replace falls back to write+unlink when rename cannot overwrite on Windows.

v0.19.4

✨ Added

Runtime

  • Nameless Signal / Clock consumers fail **OKE1072** at oke() construction and extract (A {kind} flow on "{trigger}" has no name.). Same posture as **OKE1045** for HTTP: nameless flow({ do }) is allowed until the file-tree stamp, then construction fails. Cause names the trigger; the fix points at flow("…") or a src/flows/<unit>/ export.

πŸ’₯ Breaking Changes

  • Nameless flow({ do }) no longer inherits a Signal or Clock trigger name. Flow names must be explicit flow("…") or tree-derived unit.export. oke() / extract throw **OKE1072**. Payload type inheritance from the Signal schema is unchanged.

♻️ Changed

Dev, Keel & create-oke

  • Stop tracking src/console/ui-next/dist/ in git. The Console SPA still ships in the npm/JSR tarball via prepack / scripts/publish.ts. Local create-oke file: staging builds the SPA when the folder is missing.
  • create-oke Signal / Clock consumers pass an explicit Flow name: on(noteCreated, flow("notes.onCreated", { do })) and on(digestClock, flow("notes.digest", { do })). HTTP tree files stay nameless flow({ do }).

Runtime

  • Export gzip regression baselines refreshed in budgets.json after OKE1072 / explicit Signal-Clock names (kernel edge 16.98 kB and client 4.96 kB still under the 17 kB / 5 kB absolute caps).
  • **OKE1070** now only fires for genuinely colliding names (two explicit flow("…") strings or two tree exports that stamp the same unit.export). Two nameless consumers no longer collide by inheriting the same trigger name β€” they fail **OKE1072** first.

Docs

  • Signal **Inline or named export** and **Flow name** (explicit vs tree) are gone. Signal stays named-export only: export the const, bind with on(handle, flow("explicit.name", { do })). Clock **Inline or named export** is back: write clock.every(…) inside on() for a single consumer, or export the const when several Flows share one schedule. Both Clock styles still require flow("name", { do }) (**OKE1072**). Tree unit.export stays on Routing for HTTP. OKE1070 / OKE1072 troubleshooting remains.

πŸ› Fixed

Runtime

  • Extract no longer stamps a nameless Signal / Clock consumer from a bare export const outside src/flows/<unit>/ (e.g. inbound.ts or src/signals/inbound.ts). That path now fails **OKE1072**, matching oke() and the documented tree-stamp contract.

v0.19.3

✨ Added

Runtime

  • Duplicate signal.once consumers fail **OKE1071** at oke() construction and extract when two or more **different** Flow names bind the same once signal. signal.broadcast / signal.live stay unrestricted. Cause names both Flows and the signal; the fix points at signal.broadcast vs a single Flow (replicas of one Flow are still one on() in source).

πŸ’₯ Breaking Changes

  • Two different Flows bound to the same signal.once no longer race silently. oke() / extract throw **OKE1071**. Use signal.broadcast when every Flow should receive a copy, or bind a single Flow.

♻️ Changed

Docs

  • CDC consumers docs add **Bare or enriched** (Style / When table, Bare vs Enriched worked examples, same-object honesty) to match Signal / Clock **Inline or named export**.
  • Signal and Clock **Inline or named export** now include complete Inline vs Named worked examples β€” one-file on(signal.once / clock.every, flow({ do })) versus an exported handle β€” matching CDC **Bare or enriched**.
  • Signal and Clock **Flow name** documents inherit vs explicit vs tree (flow({ do }) takes the trigger name only with no unit folder; flow("…") and src/flows/<unit>/ unit.export overwrite; collision is **OKE1070**).
  • Signal **Smallest Example** presents declare / bind / emit as independent uses of one shared handle β€” not a numbered sequence. Same framing on Once, Broadcast, Live, and Consumers.
  • Signal **Competing consumers** documents signal.once as a work queue: three differently-named Flows, one emit, exactly one race winner β€” and names signal.broadcast as the fix when every Flow should get a copy. Two different Flows on one once signal fail **OKE1071**.

πŸ› Fixed

Runtime

  • Extract **OKE1071** throws a plain Error (code plus signal.broadcast fix) instead of OkeError, so okengine/compiler stays off the kernel error and i18n graph. oke() still throws the full OkeError.

v0.19.2

✨ Added

Runtime

  • Inline on(signal.once(…), flow) / on(clock.every(…), flow) now stamp Manifest flow.trigger the same as a named const binding.
  • Nameless flow({ do }) inherits a named Signal or Clock trigger name. Explicit flow("…") and file-tree unit.export still win.
  • fx.emit(handle, payload) type-checks payload when handle is SignalDecl<T>. A string name stays unknown (runtime schema still applies).
  • Duplicate Flow names fail **OKE1070** at construction (and extract), matching HTTP / live / MCP duplicate-registration posture.
  • CDC do input (CdcPayload) always includes table, action ("created" / "updated" / "deleted" from before/after presence), and id (the table's declared primary-key value). Destructure only { before, after } when that's all you need.

πŸ’₯ Breaking Changes

  • Two Flows that share a name no longer last-write-wins. oke() throws **OKE1070**; extract hard-fails the same collision.

♻️ Changed

Docs

  • fx.id() docs and JSDoc now say **OKID**, aligned with okengine/okid and the fx / OKID reference cross-links.
  • Signal, Clock, Consumers, Routing, Errors, and fx docs cover inline on(signal.* / clock.*, flow), name inheritance, typed fx.emit(handle), and **OKE1070**.
  • Clock examples across docs, Keel, and create-oke advanced prefer named helpers (clock.every / daily / weekly); bare clock(name, opts) stays valid and is called out where the generic form is deliberate.
  • CDC consumers docs show both { before, after } and the enriched { table, action, id } form; the audit-log example uses the enriched fields.
  • Scaffold AGENTS.md and the oke-docs skeleton link to The Architecture.
  • Dropped all permanent redirects from site/next.config.ts.
  • Site headerGeometry home assertion matches the centered full-bleed hero (no left-pane lg:w-[44%] on the homepage).

v0.19.1

✨ Added

Docs

  • Homepage hero gains a prism backdrop (PrismBackdrop, ogl WebGL, adapted from React Bits β€” see site/NOTICE): a desaturated light cone masked away from the copy, capped at 1.25Γ— device pixel ratio, suspended offscreen, and frozen on one frame under prefers-reduced-motion. The cone is tinted by the element the walk is on β€” --oke-el-* resolved to sRGB and eased into the shader β€” so pinning the .gate(…) line turns the whole hero Gate emerald.

♻️ Changed

Docs

  • Homepage hero law chip is just on(Trigger) β†’ Effects (drops the muted "the one law" label beside the formula). The trailing arrow stays hidden until hover, then fades and slides in.
  • Homepage hero CTA row matches heights: both actions are h-10, same horizontal padding and text-sm, stretched on sm+ instead of centered at unequal intrinsic sizes.
  • Homepage hero is one composed surface instead of a bare headline: chip, two-count headline with a spring settle, the positioning line, and two ways in (**Read the architecture** plus a copyable bunx create-oke@latest). Below it, one merged stage frame joins the live create.ts fx walk to the eight-element lattice β€” same beat, hover a line or a slab to pin it β€” over a shared foot rail carrying the lit effect on the left and the CI-measured budgets.json facts (cold start, client runtime, routing p99) plus Bun β‰₯ 1.4.2 Β· MIT Β· v… on the right. The walk is hidden lg:flex; below lg the lattice carries the stage.
  • Homepage hero walk is real TypeScript: one create Flow through all eight elements (fx.ask / fx.send join the starter create.ts calls), tokenised at build time by the same Shiki themes as the handbook code blocks (loadHeroCodeLines, site/lib/hero-code.ts), keeps its indentation, and dims by opacity so the lit beat still reads in syntax colour. The stage frame grows with it β€” max-w-7xl, a 26 rem walk column, and 13 px code.
  • Features eight-element cards match shipped API kinds: **Flow** http Β· signal Β· cron Β· cdc; **Clock** cron Β· every Β· sleep Β· now (TTL is Store KV, not Clock); **Vault** drops aspirational fp; **AI** model Β· prompt Β· embed Β· agent (not noPii / RAG kinds); **Channel** whatsapp label; **Gate** policy Β· scope Β· rate Β· public. Descriptions and zoo Clock concern every (was TTL) stay aligned.
  • **Understand is now one page: The Architecture** (/docs/understand/the-architecture). Merges The Problem, The Model, The Vocabulary, and The Anatomy into a single narrative β€” drift β†’ one rule β†’ eight elements β†’ five-piece Flow anatomy β€” with the teaching figures placed where they prove the claim (SixSystemsDrift, FlowShape, Features, FlowTriggers). Pain-first hook, "what OKE is β€” and isn't" positioning block, then/now timeline table, single next step (Try It). Old URLs redirect. Try It stays separate.
  • Homepage restacks around a Farm-style 2Γ—2 deck (Flow simulator, live fx walk, typed createClient, oke dev terminal) plus a Cloudflare-style measured claim strip from budgets.json and a tabbed starter stage (create.ts / on-created.ts / client). Hero stays the 44/56 split with the lattice; Install lives in the deck instead of a late ship band.
  • Homepage drops the late β€œMeasured, not marketed” budgets band (BudgetsGraph, proof strip, built-with / works-with). Four hard caps stay in the hero claim strip from budgets.json.
  • Homepage hero removes the redundant "Backend" pill from the hero trust strip, keeping TypeScript and the release version badge.
  • Homepage is hero-only: a single centered column β€” copy first, lattice below (law chip, two-count headline, then the eight slabs); the headline is set large (5xl β†’ 7xl) with a wider measure so it reads as the page's single statement. The hero fills the viewport (100svh minus the nav) with the column vertically centered. claim strip, deck bands, code stage, collapse diagram, surfaces, elements, and ship CTA are removed from /. The hero copy is stripped to essentials: no kicker (the chip says it), no TypeScript/version pills, and the lattice caption is one centered line (element, what it replaces, docs link).
  • Homepage hero tagline leads with the programming model: define behavior once, then OKE derives the runtime, client, Console, and infrastructure.

πŸ› Fixed

Runtime

  • Hybrid search LSH recall: query-time candidate retrieval ranked stored K=64 SimHash packs by Hamming distance (bit_count of XOR, ORDER BY then oversample LIMIT) instead of equality against the exact bucket plus Hamming-1 neighbors. Write/query hashing was already identical; the probe never reached true neighbors (typical distance ~5–16 bits), which is why G17 precision@10 collapsed to ~0. Hamming-1 equality is no longer the candidate set. See src/bench/REPORT.md G17 for before/after numbers.

Docs

  • Homepage hero CTAs share a fixed h-10, matched 1px borders (transparent on the primary), and leading-none so **Read the architecture** and the copyable bunx create-oke@latest sit at the same height (was 40px vs 39px from text-sm / text-xs line boxes).
  • Homepage code stage keys each Shiki pane before passing the array to the client tabs β€” clears the React β€œunique key” warning on /.
  • Docs MCP tools and tests resolve understand/the-architecture after the Understand section consolidation (was stale understand/the-problem).
  • **Try It** lives at /docs/understand/try-it (after The Anatomy). The old /docs/ai/try-it URL redirects. Sidebar no longer splices it out of AI Resources.
  • Store Search G17 table and LSH retrieval copy match Hamming-rank query (was Hamming-1 / near-zero P@10).
  • Element pages still showed invoke contracts on flow() after the v0.19.0 move. Examples now put in / out / errors on http.* / call().
  • Removed unpublished site/content/_archive/get-started-legacy.

v0.19.0

Pre-1.0 minor for deliberate breakages since v0.18.5: exposure-owned invoke

contracts, Signal declaration reshape, and the full OKE error-code renumber β€”

plus Realtime, built-in hybrid search (G17 measured), OAuth / MCP authorization,

external-call tracing, and the AI provider registry. Scan by area below.

✨ Added

Runtime

  • **call(name, options)** β€” call-only Flow sugar with invoke contract on the same bag (in / out / errors / breaking + do + runtime). Exported from okengine and okengine/http.
  • **BoundaryContract** β€” shared { in?, out?, errors?, breaking? } on HTTP verb bags and mcp.tool(name, bag).
  • **OKE1605 CHANNEL_SCHEMA** β€” fx.send rejects template data that fails the template's Standard Schema (parity with Signal emit **OKE1250**).

Console β€” Flows & traces

  • Trace waterfall marks egress effects with a dashed outline when EffectEntry.external is present; tooltips and event rows show host / provider / third-party vs infrastructure.

Runtime

  • **EffectEntry.external** β€” optional { host, provider?, kind?: "third-party" | "infrastructure" } on ledger entries when an effect left the process. Driver-reported (Channel failover, AI complete/embed, Store network facets); never hostname-guessed at the ledger layer. In-process drivers (PGlite, mock AI, console Channel) omit the field.
  • **fx.fetch(url, init?)** β€” first-class outbound HTTP through fx (EffectKind "fetch", Manifest effects.fetches host refs, dry-run stub, UNDECLARED_FETCH / OKE1008). Always stamps external: { host, kind: "third-party" }. Compose with fx.step / fx.retry like other irreversible effects.
  • Browser JSON page: **Request** rail leveled to Console Call API dock IA β€” Routes fill the top as primary nav; Params Β· Body Β· Cookies Β· Headers Β· Path sit in a docked **Request** strip (Reset Β· **Send**). Body supports **Form** (application/x-www-form-urlencoded) or **JSON** (application/json) with live syntax highlight (same key/string/number colors as the response view) and pretty-print on blur; Send posts when the body is set (or the selected route method allows a body). Route leaf clicks only select the target (method / path); the response view updates on **Send**. One Send persists option edits and refetches; per-section Apply removed. Path chapter hides until a parameterized route is selected. Header shows the handled-request auth mark beside status, latency, and cache. Collapsed thin label is **Request**.
  • **createClient({ auth }) β†’ api.auth** β€” session options on createClient attach AuthClient (merged over the auth unit Flows). createAuthClient + bind remains the escape hatch. Thin createServerClient + tokenFromRequestCookies for SSR.
  • **UI authorize DX** β€” api.auth.authorize({ all | any }), React Can / Cannot / useAuthorize, forbiddenScopes helper. Gate on Flows remains real authz.
  • **Binary responses** β€” per-call { response: "blob" | "arrayBuffer" } on Flow invokes.
  • **CSRF soft-require** β€” when gate.auth.cookies.enabled, prod refuses boot without the csrf plugin; dev/test warn. csrf exported from okengine/plugins.
  • **Client auth level-up** (okengine/client/auth): createAuthClient with secure-by-default mode: "bearer" | "cookie", memory persist (optional sessionStorage / loud localStorage), signIn.* / signUp.* / completeChallenge / signOutβ†’auth.revoke, UI-only hasScope / can, tenancy header helpers, denial narrowers, and memorySession.subscribe / persistSession. Cookie mode refuses Storage dual-store and warns unless csrfConfigured.
  • **auth.me enrichment** β€” returns scopes, tenantId, apiKeyId, optional sessionFresh for UI chrome (Gate on Flows remains real authz).
  • **Typed JSON streams** β€” flow({ stream: true }) stamps $routes.stream; createClient yields AsyncIterable for non-live SSE (fx.json.stream). Shared sse.ts pump.
  • **Honest ambient client** β€” GET /_oke/client.json emits type strings + live/stream stamps; oke client add writes oke-client.d.ts **and** oke-client.routes.ts.
  • Transport: credentials, AbortSignal / timeout via AbortSignal, raw BodyInit / FormData / Blob bodies. useLiveQuery accepts listPath to derive /live.
  • JSR exports ./client/auth and ./client-react; optional react peerDependency.

Dev, Keel & create-oke

  • create-oke Notes starters ship src/vault.ts with stack + app vault.secret / vault.config contracts (NOTES_VAULT) and pass them to oke({ secrets }), so Console Vault lists DATABASE_URL, SMTP, Redis, files, console secret, and cleartext configs β€” values still resolve from .env.local, process env, oke vault set, or dev: / vault.fromDocker fallbacks. oke ai setup prefers src/vault.ts (and inserts into NOTES_VAULT) when wiring provider API keys.
  • **Advanced starter** β€” cookie gate.auth, csrf + cors + passkey, web createClient({ auth: { mode: "cookie" } }) + <Can> chrome demo.
  • oke dev asks once to run oke db seed when a seed module exists and .oke/state.json has not recorded that seed identity (TTY only). Successful oke db seed (including live **s**) marks the identity so the prompt does not repeat.
  • oke dev prompts one-by-one for Vault boot gaps (same set as VaultBootError) and writes values into .env.local before the app starts.

Docs

  • fx reference documents fx.fetch, effects.fetches, and driver-reported EffectEntry.external (third-party vs infrastructure) on traces.
  • Errors reference lists **OKE1008** (UNDECLARED_FETCH) and **OKE1009** (UNDECLARED_EMBED); the undeclared-effect Callout covers 1001–1009.
  • Vault overview notes create-oke Notes src/vault.ts contracts + oke({ secrets: NOTES_VAULT }) so Console lists secrets and configs while values stay in .env.local / built-in vault / oke vault set.
  • CLI / Vault / Store seeding docs cover first-boot seed confirm and interactive Vault gap fill; OpenRouter recipe notes create-oke / oke ai setup write the API token to .env.local + vault.secret, and oke dev asks when still missing.
  • Client Auth / Calling / React / CSRF / ClientLoop updated for createClient({ auth }), authorize / Can, binary downloads, CSRF soft-require, and SSR cookie helper.
  • Client Auth handbook rewritten for createAuthClient (secure defaults, methods, UI-only scopes). Calling / React / plugins notes updated for routes module, streams, and auth DX.
  • New **04 Client** handbook group after Extend (Reference β†’ **05**, AI Resources β†’ **06**): Overview, Calling, Auth, Live, React at [HTTP](/docs/elements/flow/http) page depth; permanent redirect from /docs/reference/client β†’ /docs/client; hub Cards + llms index + sidebar icons; Client folder unwrapped flat under 04 CLIENT (same as Understand / Reference). Examples use a commerce domain (bookings, orders, shipments, inbox) instead of health / notes scaffolding; createClient base URLs use vault.env from okengine/vault (PUBLIC_API_URL) β€” subpath imports, not the root barrel.
  • Elevated [Reference](/docs/reference) to [HTTP](/docs/elements/flow/http) page depth: created missing [CLI](/docs/reference/cli) and [Security](/docs/reference/security) (Host/Origin/allowedHosts, planes, MCP posture); upgraded fx / Errors / Environment Variables / Configuration skeleton (one rule, Steps, Troubleshooting, Next); aligned hub Cards + meta.json + llms index order.
  • Elevated [AI](/docs/elements/ai) (overview, Models, Prompts, Agents, MCP) to [HTTP](/docs/elements/flow/http) page depth: Smallest Example + Progressive Patterns, Declaration / fx tables, teaching figures (AiBlocks, AiGuardrails, AiPiiEgress), per-environment drivers, and Troubleshooting with verbatim errors (OKE1005, AiSchemaValidationError, budgets, PII build gate). Corrects invented surfaces (ai.prompt, template:, agent instructions / top-level maxCostPerRun / in/out, MCP at :6530/api/mcp) to real APIs (model.prompt, budget.maxCostPerRun, fx.ask / fx.run, mcp.tool on :6535/mcp, ai.mcpServer allowlists).
  • AI teaching figures raised to GatePipeline quality: AiGuardrails (scenario strip, status pips, footer holds β€œChecking guardrails…” until outcome), AiPiiEgress (full ask β†’ check β†’ verdict phase strip + packet gate + footer), AiBlocks (accurate openrouter bind, out validate, Flow tool names, maxSteps halt pips).
  • Elevated [Channel](/docs/elements/channel) (overview, Email, SMS, WhatsApp, Push, Receipts) to [HTTP](/docs/elements/flow/http) page depth: Smallest Example + Progressive Patterns, Declaration / fx.send tables, ChannelPhysics teaching figure, per-environment drivers, and Troubleshooting with verbatim boot / OTP errors. Corrects invented surfaces (channel.email("name", { subject, body }), fx.sendWebPush, fx.channel.getReceipt, oke_receipts, Twilio / SES driver ids) to real APIs (channel.email().template, catalogs, fx.send / sendOtp / verifyOtp / deliverOtp). Splits WhatsApp into its own page; documents push drivers as boot-manual (openFcmChannel / openWebPushChannel).
  • Elevated [Vault](/docs/elements/vault) (overview, Secrets, Config, Key Rotation) to [HTTP](/docs/elements/flow/http) page depth: Smallest Example + Progressive Patterns, Declaration / Options / fx.vault tables, resolution chain + Redacted teaching figures (VaultResolution, VaultRedacted), per-environment drivers, vault.env helpers, version vs master-key rotate, CLI reference, and Troubleshooting with verbatim VaultBootError / seal / backend errors. Corrects invented surfaces (vault.rotation, config default:) to real APIs (fx.vault.rotate, dev:).
  • Vault teaching figures raised to GatePipeline quality: VaultResolution (contract strip, status pips, footer holds β€œResolving…” until outcome), VaultRedacted (full phase strip + substring scrub), new VaultRotate contrast (version DEK vs master KEK) on Key Rotation.
  • Elevated [Gate](/docs/elements/gate) (overview, Authentication, Authorization, RLS, Rate Limits, Tenancy) to [HTTP](/docs/elements/flow/http) page depth: Evaluation Order + denial envelopes, Sessions & Cookies / API Keys accordions, Module:Action permissions, Gateβ†’SQL identity stamp (oke.gate / oke.user / oke.has_scope / oke.tenant), per-strategy rate tabs, Resolution Sources, Store RLS helpers, and Troubleshooting with verbatim GateBootError / i18n messages. Sidebar: Auth β†’ Authorization β†’ RLS β†’ Rate Limits β†’ Tenancy.
  • GatePipeline teaching figure: footer stays on β€œEvaluating chain…” until the final beat (no premature β€œEvery gate passed” / β€œDenied”); status pips mark pending Β· pass Β· deny Β· skipped across the left-to-right walk.
  • Elevated [Clock Β· Durable Sleep](/docs/elements/clock/sleep) to HTTP-trigger docs depth: curl in Smallest Example, Sleep Reference + duration units, Park Physics, With Steps tabs (checkpoint / HTTP body + sleep / Signal consumer), Nested Calls, Wake Early, Non-durable & Tests (createTimeTravel, journal drivers), and expanded Troubleshooting (JournalLeaseBusy, orphan scan, unknown durations, nested sleeper).
  • Elevated [Clock Β· Schedules](/docs/elements/clock/schedules) to HTTP-trigger docs depth: Helper Reference, Timezone Resolution, Binding & Input, per-helper tabs (daily / hourly / weekly / monthly / cron / every), Per-tenant
  • Leader Lock detailed sections, Store Lifecycle & Console accordions (status, Console actions, DST, effective vs declared), and expanded Troubleshooting (cron at, paused rows).
  • Clock schedules + intervals docs merged into one [/docs/elements/clock/schedules](/docs/elements/clock/schedules) page (helpers, every, per-tenant, catch-up, DST); overview teaching figure shows clock.every / clock.daily + zone from oke({ clock }).
  • Elevated Clock element docs (/docs/elements/clock) to HTTP / Store depth: overview + Schedules / Intervals / Durable Sleep with Smallest Example, Progressive Patterns, options tables, teaching figures (ClockSchedules, ClockCatchUp, ClockSleep), real APIs (timezone, clock.perTenant, fx.clock.sleep(label, duration)), catch-up "one", leader locks, and Troubleshooting. Removes invented surfaces (tz, one-arg sleep, jitter on clock()).
  • Store element docs (/docs/elements/store) rewritten to the HTTP / Search page bar: overview + SQL / KV / Files with Smallest Example, Progressive Patterns, reference tables, teaching figures (StoreFacets, StoreKvTtl, StoreFilesVariants, StoreSeeding), real fx.store(decl) APIs, and Troubleshooting. Removes invented surfaces (fx.store.kv, presignPut, transform, Drizzle .query on the handle).
  • Elevated [Store Β· KV](/docs/elements/store/kv) to HTTP-trigger docs depth: response envelope in Smallest Example, method tabs (get / set / delete / list / ttlMs), Namespaces, Durable Namespaces accordions, TTL Physics, Tenant Scoping (OKE1810), key-prefix / effects layers, and expanded Troubleshooting (SCAN, invented incr / setNx).
  • Elevated [Store Β· Files](/docs/elements/store/files) to HTTP-trigger docs depth: response envelope in Smallest Example, blob-op tabs (put / get / delete / list), Object Keys, putImage / Image Pipeline accordions (variant naming, decode guards, encode fallback), drivers + S3 env notes, and expanded Troubleshooting (Invalid object key, missing image source, single-encode variant rule).
  • Elevated [Store Β· Search](/docs/elements/store/search) to HTTP-trigger docs depth: Declaring Columns / Running Search tabs, Fusion + Backfill accordions, dedicated Rerank + Requirements, corrected meta.engine vs fusedBy honesty, and expanded Troubleshooting (lsh without fusion).
  • OKID reference documents prefix / OKID_MAX_PREFIX_LENGTH and the prefix + sortable composition.
  • Consolidated local-inference docs into OpenRouter + Models (BYO openai-compatible); removed the standalone Local AI / Ollama recipe pages. Added OpenRouter recipe recommending openrouter/free; rewrote Models docs (Verified providers / Limited compatibility).
  • OpenRouter recipe documents router aliases (openrouter/free, auto, pareto-code, fusion, bodybuilder, ~…-latest) with OKE ai.model examples and links to OpenRouter’s router guides.
  • create-oke template .env.example / core.ts AI notes and Keel example src/core/ai.ts document registry cloud (openrouter) vs self-host openai-compatible + explicit baseUrl.
  • Docs sidebar OpenRouter recipe uses the official OpenRouter glyph from [openrouter.ai/brand](https://openrouter.ai/brand) instead of Lucide Globe.

Dev, Keel & create-oke

  • Notes starters (standard / advanced) declare .searchable() on title / body. When oke ai setup / create-oke picks an embed model, setup stamps bare body.embed() plus oke({ store: { search: { embed: { model: embedModel, dims: 768 } } } }) (distinct from the index-facet ai.embed("docs", …) pipeline).

πŸ’₯ Breaking Changes

Runtime

  • **Invoke contracts leave flow()** β€” in / out / errors / breaking are authored on the exposure, not on flow(). Use http.post({ in, out, errors }) (or http.get("/path", { … })), call("unit.export", { in, out, do, … }) for call-only work, and mcp.tool("name", { in, out, errors }) for MCP. Signal / Channel keep emit schema (Channel schema is enforced at fx.send as **OKE1605** / CHANNEL_SCHEMA). Manifest still stores flat flows.*.in/out/errors/breaking as a projection. flow() throws if those keys are passed.

Docs

  • Flow / HTTP / Consumers / Signal / errors reference updated for exposure-owned invoke contracts vs emit schema, plus call() call-only sugar.
  • **OKE error codes renumbered into domain ranges** (full break; no legacy carve-out). Every framework code is reassigned under: Kernel 1000–1099 Β· Store 1100–1199 Β· Signal 1200–1299 Β· Clock 1300–1399 Β· Gate 1400–1499 Β· Vault 1500–1599 Β· Channel 1600–1699 Β· AI 1700–1799 Β· MCP+Tenancy 1800–1899 Β· Compiler 1900–1999. Definitions now carry a domain field; registry tests enforce uniqueness **and** range-correctness, discovering lazy errors-*.ts chunks automatically (no hand-maintained LAZY_DEFS list). Historical ## v… changelog text still cites pre-renumber numbers. **OKE1020 changed meaning:** before this renumber it was UNDECLARED_EMBED; after this renumber it is NO_EFFECTS_DECLARED. Anyone matching or bookmarking β€œOKE1020” without a key name must re-check β€” embed is now **OKE1009**. | Key | Old | New | Domain | | ------------------------- | ---- | ---- | ----------- | | UNDECLARED_READ | 1001 | 1001 | kernel | | UNDECLARED_WRITE | 1002 | 1002 | kernel | | UNDECLARED_EMIT | 1003 | 1003 | kernel | | UNDECLARED_SEND | 1004 | 1004 | kernel | | UNDECLARED_ASK | 1005 | 1005 | kernel | | UNDECLARED_SECRET | 1006 | 1006 | kernel | | UNDECLARED_CALL | 1007 | 1007 | kernel | | UNDECLARED_FETCH | 1019 | 1008 | kernel | | UNDECLARED_EMBED | 1020 | 1009 | kernel | | NO_EFFECTS_DECLARED | 1008 | 1020 | kernel | | ADOPT_BARREL_STALE | 1009 | 1030 | kernel | | HTTP_PATH_UNRESOLVED | 1010 | 1040 | kernel | | HTTP_ROUTE_DUPLICATE | 1011 | 1041 | kernel | | HTTP_FLOW_UNNAMED | 1012 | 1045 | kernel | | LIVE_EXPOSURE_DUPLICATE | 1013 | 1050 | kernel | | MCP_TOOL_DUPLICATE | 1018 | 1060 | kernel | | DOMAIN_SCHEMA_MISSING | 1101 | 1110 | store | | LIVE_RESUME_GAP | 1014 | 1210 | signal | | ORPHAN_EMIT | 1042 | 1240 | signal | | SIGNAL_SCHEMA | 1043 | 1250 | signal | | TENANT_REQUIRED | 1015 | 1810 | mcp_tenancy | | TENANT_NOT_MEMBER | 1016 | 1820 | mcp_tenancy | | TENANT_UNKNOWN_SCOPE | 1017 | 1830 | mcp_tenancy |
  • UNDECLARED_EMBED no longer shares a number with TENANT_REQUIRED (tenant codes moved to **OKE1810–1830**; embed is **OKE1009**).
  • **flow() invoke contracts** β€” in / out / errors / breaking must live on the exposure (http.*(…), call(…), mcp.tool(…)). Passing them to flow() throws at definition time. Call-only flows use call(name, { in, out, do, … }) (exported from okengine and okengine/http).

♻️ Changed

Runtime

  • Export gzip regression baselines refreshed in budgets.json after the dependency refresh (kernel edge 16.98 kB and client 4.96 kB still under the 17 kB / 5 kB absolute caps).
  • Dependency refresh: React ^19.3.0, zod ^4.6.1, Vite ^8.3.0, oxc ^0.149.0, oxlint ^1.82.0, oxfmt ^0.67.0, @clack/prompts ^1.8.0 (oke docker clean narrows 1.8 cancel symbols), plus Console patches (TanStack Router/Virtual, happy-dom, Hugeicons). Drizzle stays on intentional 1.0.0-rc.5-* (npm latest is still 0.x).
  • Kernel edge gzip budget is **17 kB** (was 16 kB). Measured ~17.0 kB after hybrid-search embed effects, signal surface growth, and fx.fetch / EffectEntry.external (fetch body lazy-loaded off the edge profile). AGENTS.md / KERNEL_EDGE_BUDGET_BYTES aligned.
  • Store-only oke() lazy-loads the browser JSON page (json-code-block) on app.fetch so graphs that never serve HTTP do not pin the traces-language HTML/CSS chunk (~65 kB β†’ ~51 kB gzip).
  • fx.fetch host parsing + dry-run stub live in a lazy fx-fetch chunk so cold edge / Store-only graphs that never call outbound HTTP avoid that code.
  • createClient({ auth }) api.auth Proxy implements has so "me" in api.auth (and other unit Flow checks) match get semantics.
  • Dependency refresh (2026-09-05): Console / tooling minors + patches (zod ^4.5.4, TanStack Query/Router/Form, Vite ^8.2.2, Playwright ^1.63.0, oxlint / oxfmt / oxc-parser ^0.148.0, PGLite ^0.5.8, …); majors @tanstack/react-table ^9.2.4, shadcn ^4.21.0, shiki ^4.4.3. Drizzle stays on intentional 1.0.0-rc.5-* (npm latest is still 0.x).
  • Client gzip budget raised to **5 kB** (was 4 kB) so shared SSE + stream open fits the measured okengine/client graph; AGENTS.md budget table aligned.
  • create-oke Vite proxy includes /auth alongside /notes, /health, /_oke.
  • Minimum Bun is β‰₯ 1.4.2 (engines.bun, CI bun-version, feature-gate error messages). @types/bun / bun-types track "latest". Generated Dockerfiles stay on the oven/bun:1.4 line.

Dev, Keel & create-oke

  • create-oke and Notes templates track the same React 19.3, zod, Vite, and oxc bumps; Keel PGLite aligned to ^0.5.8 / pgvector ^0.0.9.
  • bun run budgets:core runs the kernel-edge + client gzip gates. Required after src/kernel/ / src/client/ / src/compiler/ / src/validation/ / src/release/limits.ts / measure.ts changes (agent workflow + oke-ship). Optional git hook: git config core.hooksPath .githooks.
  • Keel flows, bindCrud, auth HTTP bindings, Console seed invoke host, and remaining kernel / test call sites finish the invoke-contract migration off flow({ in, out, … }).
  • oke dev streams Docker Compose pull / create / start progress into the boot status lines (and live keyboard **up**) instead of a silent docker compose up… wait.
  • Compose default image pins: RustFS 1.0.0-rc.5, Mailpit v1.31.1, PgDog v0.1.57 (Meilisearch v1.53, Traefik v3.7, nginx 1.31-alpine, floating postgres/redis/caddy unchanged). No images.ai / local inference pins β€” AI is OpenRouter (recommended) or BYO openai-compatible URL. create-oke templates + Keel stack aligned for the non-AI pins.
  • **Keel default AI** is OpenRouter Β· openrouter/free (no Compose AI service). OPENROUTER_API_KEY is a Vault contract without a dev: stub so first oke dev asks for it. Self-host = set OKE_AI_URL / baseUrl on openai-compatible yourself.
  • create-oke / Notes starter dependency refresh (PGLite, Vite, oxc-parser, zod; Drizzle RC pins unchanged).
  • oke ai setup (and create-oke AI wizard) emit real registry provider names on ai.model (e.g. openrouter, groq) with matching API key env vars; known cloud base URLs are omitted so the registry resolves them. OpenRouter defaults to openrouter/free. Menu lists verified registry providers plus Gemini (limited compatibility). Anthropic stays native driverId: "anthropic".
  • create-oke **AI setup β†’ Recommended** (and --yes --ai) defaults to OpenRouter Β· openrouter/free. Customize / oke ai setup offer cloud registry providers plus lmstudio / custom (BYO OpenAI-compatible URL) β€” not local Docker engines.
  • create-oke **Recommended** prompts for OPENROUTER_API_KEY (same as Customize cloud path) and writes it into .env.local.
  • **AI Provider** select (create-oke Customize + oke ai setup) leads with OpenRouter and lists the full cloud registry set; OpenRouter **Select model** includes router aliases (free / auto / pareto-code / fusion).
  • create-oke engines.bun and Notes starter GitHub Actions use Bun 1.4.2.
  • PgDog Compose healthcheck polls every **2s** (was 5s) with a **2s** start period; compose health wait timeout raised to **90s** so cold Postgres + PgDog can finish before the board moves on.

Docs

  • Site deps: fumadocs 16.15.8, lucide ^1.44.0, React 19.3, zod ^4.6.1.
  • Scrubbed leftover "ten exports" / "ten words" marketing: landing vocabulary band, docs hub Vocabulary card, and site EXPORTS now use "core programming vocabulary" and include call (11 names, matching AGENTS.md).
  • CLI docs note that oke dev streams Compose pull / create / start progress into boot status lines.
  • Models docs drop the incorrect meta registry row; Cloudflare and Meta are listed as omitted hosts that always need an explicit baseUrl.
  • PgDog recipe healthcheck table matches the 2s interval / 20 retries.
  • CLI docs drop the old oke dev TTY live-keys bar (?/r/s/q/u/x); quit with Ctrl+C; seed via oke db seed or the first-boot prompt.
  • Aligned machine-facing agent surfaces with the live handbook IA: llms-txt When-to-use prose, docs MCP oke.docs.get examples, AGENTS.md authority table (Understand Β· Elements Β· Client Β· Reference Β· AI Resources), skills path maps (oke-ship / oke-docs / oke-docs-update), and create-oke scaffold ports (adds Docs MCP **6536**). Removed empty docs/concepts/.
  • Site deps: fumadocs 16.15.7, framer-motion ^13.2.0, cnfast ^0.2.0, lucide / zod / PostCSS aligned; recipe + configuration docs mirror the new RustFS / Mailpit / PgDog pins.
  • HTTP docs default to pathless triggers and nameless Flows β€” on(http.get(), flow({ do })) β€” with an explicit [When to omit Β· when to pass](/docs/elements/flow/routing#when-to-omit--when-to-pass) table on Routing. Teaching examples across Flow, Gate, Vault, Store, Clock, Signal, and recipes omit path/name unless control requires them (barrels, http.resource, custom live SSE, auth plugin URLs).
  • Docs sidebar **Reference** is flat under 05 REFERENCE (no accordion group); the /docs/reference Overview landing is hidden from the nav list.
  • Docs sidebar drops stage **Build**; stages renumber to Extend 03 Β· Operate 04 Β· Reference 05 Β· **AI Resources** 06 (MCP Β· Skills Β· llms.txt). **Try It** sits under Understand after The Anatomy; /docs/ai Overview is hidden from the nav list.
  • Docs sidebar stage **Extend** is 03 again (Plugins / Providers / Recipes after Elements); Operate β†’ 04. Handbook index card group updated to match.
  • Tightened [Clock Β· Schedules](/docs/elements/clock/schedules) in place (still three Clock pages): collapsed duplicate Helpers deep-dive into Helper Reference, compressed per-tenant / leader lock / Store lifecycle & Console. Nav stays Overview Β· Schedules Β· Durable Sleep.
  • Site Next / PostCSS configs are next.config.ts (typed NextConfig) and postcss.config.ts instead of *.mjs.
  • Moved docs sidebar stage **Extend** from 05 to 03 (Plugins / Providers / Recipes after Elements); Build β†’ 04, Operate β†’ 05. Handbook index card groups updated to match.
  • Renamed Signal delivery docs to match helpers: /docs/elements/signal/once (was queues), /broadcast (was pubsub), /live (was streams). Cards, sidebar, and cross-links updated.
  • Installation / Try it / README badges and agent contracts document Bun β‰₯ 1.4.2.
  • Rewrote Signal element docs (/docs/elements/signal + Once / Broadcast / Live) for signal.once / broadcast / live (HTTP-shaped helpers): progressive patterns, options tables, lease / retention / drivers honesty, real error codes (OKE1240 Β· OKE1250 Β· OKE1210), teaching figures, and Troubleshooting. Corrected deadLetter (boolean, not a queue name) and live exposure via http.live / api.live (not invented EventSource paths).
  • Elevated [signal.once](/docs/elements/signal/once) to HTTP-trigger docs depth: delivery / binding / emit reference, lease reclaim and ordering accordions, failure-reason + DLQ shapes, idempotency with durable + fx.step, and expanded Troubleshooting (OKE1001 Β· OKE1240 Β· OKE1250). Dropped inaccurate β€œexponential” retry wording β€” attempts requeue with no delay backoff.
  • Signal Β· Live (elements/signal/live): rewritten to the HTTP page’s depth β€” three-step Smallest Example, Progressive Patterns, Options Reference, Exposure (filtered / custom match / live queries / uniqueness), Emit, Retention, Resume, Client subscription (api.live / useLive), What live is not, expanded Troubleshooting.
  • Signal Β· Broadcast (elements/signal/broadcast): rewritten to the HTTP page’s depth β€” three-step Smallest Example, Progressive Patterns, delivery reference + options, Fan-out Physics, Emit and Effects, Subscribers tabs, Choosing Physics accordions, and expanded Troubleshooting (OKE1240 Β· OKE1250 Β· retention type error Β· browser vs Flow consumers).
  • Signal Β· Broadcast teaching figure (SignalBroadcastFanout): ambient demo that one emit fans an independent copy to every active subscriber while an offline listener misses the event (no retained tape) β€” peers SignalOnceLease / SignalLiveReplay on once / live.

πŸ”₯ Removed

Runtime

  • Browser JSON page removes interactive Authentication (header key + rail Inherit/Custom). Handled-request auth mark in the strip remains. Re-add later with a clean plan.
  • Dropped incorrect meta OpenAI-compat registry entry (https://api.meta.ai/v1). Meta’s Llama OpenAI-compat API was retired; the hardcoded host was never the historical Llama URL and is not a verified chat-completions endpoint. provider: "meta" without baseUrl now fails loud (same posture as Cloudflare). Removed from oke ai setup / create-oke menus.

πŸ› Fixed

Runtime

  • Kernel edge gzip is back under the 17 kB cap after exposure-contract landing (+395 B gzip over the cap). OKE1605 CHANNEL_SCHEMA lives in a lazy errors-channel chunk (channel runtime is not on the edge profile); on() inlines exposure-contract stamping so boundary-contract helpers stay off that graph. lookupOkeError(1605) still resolves.
  • **$routes / typed client after exposure-owned contracts** β€” http.* / mcp.tool preserve the authored { in, out, errors } bag type, and on() projects it onto FlowDef (parity with call()). Fixes createClient<typeof app> treating inputs as ClientCallOpts and dropping declared error narrowing (e.g. Notes NotFound).
  • Shared Postgres holder .close() test awaits the async no-op (Bun.SQL returns a Promise; pool identity is unchanged).
  • SqlStoreHandle surface allowlist includes search (hybrid SQL search).
  • oke doctor PII ask fixture uses a third-party provider (anthropic) β€” openai-compatible is infrastructure and correctly skips the gate.
  • **OKE1810** no longer collides with UNDECLARED_EMBED (embed is **OKE1009**).

Dev, Keel & create-oke

  • Keel attachments upload/delete: restore missing ).gate(member), closers from the exposure-contract migration (syntax broke examples/keel typecheck).
  • create-oke Notes PUBLIC_API_URL no longer uses dev: "" β€” vault boot treats empty strings as gaps, so oke dev failed with VaultBootError: PUBLIC_API_URL. Templates now default to http://127.0.0.1:6530 (same as OKE_APP_URL); Vite web still leaves VITE_API_URL unset for the same-origin proxy.
  • create-oke Customize / Reuse no longer drops the AI API token after the wizard: the live aiApply (with apiKey) is applied so .env.local gets OPENROUTER_API_KEY=… (etc.) instead of leaving # OPENROUTER_API_KEY= empty. Reuse re-prompts for the token (prefs never store secrets). oke ai setup / create-oke also declare vault.secret(<apiKeyEnv>) (no dev: stub) so a missing key is a Vault gap on oke dev and shows in Console Vault.
  • oke dev quit / compose teardown no longer floods the TTY with ERR_POSTGRES_CONNECTION_* / SharedPostgresPausedError: shared Bun.SQL pools pause with a fail-soft facade, and fleet scheduler heartbeats swallow pause / disconnect errors.
  • First-boot oke db seed inside oke dev no longer leaves a dead shared Bun.SQL pool: journal / clock / instances close() on the shared client is a no-op (process-owned via closeSharedPostgresClients). Previously seed stop closed the cached pool, then Console reuse hit PostgresError: Connection closed and exited the session.

Docs

  • Store Files / KV wording no longer trips the competitor-mention gate on an accidental peer-name substring in ordinary English (β€œhonour” / past tense).

πŸ’₯ Breaking Changes

Runtime

  • Signal declarations use HTTP-shaped helpers: signal.once(name, opts?), signal.broadcast(name, opts?), and signal.live(name, opts?). The callable signal(name, { delivery }) form is removed. Manifest delivery is unchanged (compiler extracts it from the helper name).
  • Removed the native ollama AI driver (driverId: "ollama" / drivers.ai: "ollama"). Package paths okengine/drivers/ai-ollama and okengine/drivers/ollama are gone. Use openai-compatible + your own baseUrl / OKE_AI_URL for any OpenAI-shaped /v1 (including former Ollama / llama.cpp / vLLM / SGLang servers).
  • Dropped first-class Compose / wizard support for llama.cpp, Ollama, vLLM, and SGLang: no Docker recipes, no images.ai default pin, no oke ai setup --provider llama-cpp|ollama|vllm|sglang, no --pull / Ollama detect helpers. Migration: remove images.ai, set drivers.ai / ai.model to openai-compatible with OKE_AI_URL (or a cloud registry provider such as OpenRouter). Leftover images.ai pins fail recipeFor() until removed.

Kernel

  • Require named clock declarations instead of bare every(interval) trigger constructors: on(clock.cron(...), flow), on(clock.every(...), flow), etc.
  • Require store table receivers (db.table(handle).changed(column) / table.changed(...)) for CDC triggers instead of bare table(name, store?).

Runtime

  • When twoFactor() is plugged and the account has 2FA enabled, email/password and username sign-in withhold session tokens and return { twoFactorRequired, challengeId, method, userId } instead.
  • auth.twoFactorVerify requires { challengeId, code } (bound to the server-issued login challenge). Unbound { userId, code } is no longer accepted.
  • passkey register / authenticate options now return a ceremony sessionId; register and authenticate bodies must echo that sessionId with the challenge (challenge is bound to the ceremony session and expires in ≀5 minutes).

πŸ”₯ Removed

Dev, Keel & create-oke

  • oke dev TTY live controls bar (? help Β· r refresh Β· s seed Β· q quit Β· u up Β· x stop) and the Ink DevLive / dev-controls helpers. Session stays up after Ready; quit with **Ctrl+C**. Seed with oke db seed or the first-boot prompt. Compose lifecycle stays on boot / session quit.
  • Docker recipes + pins for llama.cpp, Ollama, vLLM, and SGLang (src/docker/recipes/{llama-cpp,ollama,vllm,sglang}.ts, ollama-pull/url, create-oke LLAMA_CPP_IMAGE / OLLAMA_IMAGE / VLLM_IMAGE / SGLANG_IMAGE). Compose no longer manages inference.
  • Local AI wizard paths, RAM catalogs, and oke ai setup --pull / --no-pull.

Docs

  • Deleted [Local AI](/docs/recipes/local-ai); /docs/recipes/local-ai redirects to [OpenRouter](/docs/recipes/openrouter). AI docs point at OpenRouter / registry cloud / BYO OKE_AI_URL.
  • Dropped [Manifest](/docs/reference/manifest) and [Architecture](/docs/reference/architecture) reference pages β€” mental model lives under **01 Understand**; permanent redirects β†’ [The Model](/docs/understand/the-model). Ports / planes stay on [Security](/docs/reference/security); hub Cards, meta.json, sidebar icons, and llms index updated.
  • Removed **04 Operate** and the entire Deployment section (/docs/deployment β€” Docker, Docker Swarm, Kubernetes, reverse proxy). Sidebar sections renumbered: Reference is now **04**, AI Resources **05**. Cross-links retargeted to Recipes / Configuration / Security.
  • Dropped all permanent redirects from site/next.config.ts (legacy Signal delivery paths, Flow jobs β†’ consumers, and old Local AI recipe URLs).

Kernel

  • Removed bare top-level every(interval) export from kernel triggers and public entrypoints (okengine, okengine/full).
  • Removed bare top-level table(name, store?) export from kernel triggers and public entrypoints (okengine, okengine/full).

✨ Added

Runtime

  • Built-in hybrid SQL search on store.schema.table() columns: field.text().searchable({ weight? }) (BM25F) and separate .embed({ model?, dims }) (async LSH). fx.store(db).search(table, { query, fuse?, rerank?, …listFilters }) reuses parseListQuery. Default fusion is RRF with **k = 60** (Cormack et al., SIGIR 2009); weighted fusion is opt-in. fx.embed(model, text) is a distinct effect kind from fx.ask (effects.embeds). CDC embed flows auto-register at boot when the Manifest has any .embed() column (writer flows stay embed-free). oke db search-backfill <table> opens a live SQL connection and rebuilds corpus stats / embeddings (never auto on push). PostgreSQL 15+, zero required extensions. **G17** (live Postgres): latency + precision@10 vs exact cosine published in src/bench/REPORT.md β€” LSH recall vs exact is near-zero on that corpus; treat LSH as a candidate hint, not HNSW.
  • Project default for field .embed() via oke({ store: { search: { embed: { model, dims } } } }). Bare .embed() inherits; per-field { model?, dims? } overrides. Extract stamps concrete { model, dims } on Manifest columns and fails loud (SearchConfigError) when either is still missing.
  • twoFactor step-up / change-method / confirm-change / request-email-otp surfaces; shared pending-challenge + step-up stores on Gate auth context; email OTP as a configurable second-factor method.

Kernel

  • Added ClockTrigger interface and isClockDecl type guard for binding named clock declarations directly to on(clockDecl, flow).

Docs

  • Rewrote Store Search docs for built-in hybrid search, with a prominent side-by-side of list-grammar ?search=/?q= (LIKE) vs hybrid query (BM25/LSH).
  • Published G17 measured latency / LSH precision@10 / corpus-size guidance on Store Search (honest near-zero LSH recall vs exact cosine; Seq Scan EXPLAIN at 100k).
  • Documented project-wide oke({ store: { search: { embed } } }) default for bare .embed() plus per-field overrides.
  • Added "The Anatomy" documentation page under Understand (/docs/understand/the-anatomy) detailing the five components of on(trigger, flow) (on, trigger, flow, do, fx) and mapping the five element triggers with timeline resolution.
  • Added modular subpages for all eight core elements (Flow, Signal, Store, Clock, Gate, Vault, Channel, AI) covering architecture, execution patterns, and driver bindings.
  • Added new "Understand" section (/docs/understand) covering the problem, the model, the vocabulary, and architectural drift.
  • Added interactive SixSystemsDrift component illustrating architectural drift across fragmented backend stacks.
  • Added ScrollToTop helper component to the documentation layout.

♻️ Changed

Compiler

  • Updated compiler trigger extraction (extract.ts, effects-infer.ts) to infer triggers from named clock bindings and store table receivers (table.changed()).

Docs

  • Merged "See It Work" into "The Anatomy" (/docs/understand/the-anatomy) by incorporating the timeline resolution section into the anatomy guide and retiring /docs/understand/see-it-work.
  • Dissolved legacy Concepts section into modular Element guides (elements/flow, elements/flow/routing) and Reference (reference/fx, reference/manifest, reference/architecture).
  • Upgraded FlowShape figure (flow-shape.tsx) with interactive stage physics, active element triggers (including MCP), and nameless flow auto-derivation annotations.
  • Enhanced Flow documentation with interactive trigger visualizer (flow-triggers.tsx), step-by-step quickstart, comprehensive execution options (compensate, retry, cache, plane), schema validation guides (Standard Schema, Drizzle ORM v1 subpaths, shapes.ts), and dedicated Shiki focus/highlight styles.
  • Updated agent CI guidelines across .cursorrules, AGENTS.md, and skill definitions to prevent automatic CI execution after implementations.
  • Flow Overview (elements/flow): rewritten to the HTTP page’s depth β€” Smallest Example Steps, Progressive Patterns, trigger table + capability cards, verified flow() options (cache auto for read-only, NotFound β†’ 400 not 404), fx door, call-only / internal, plane / retry / OKE1020 troubleshooting.

Dev, Keel & create-oke

  • Migrated all examples (keel), starters (create-oke standard and advanced templates), and test fixtures to the consolidated clock and table trigger syntax.

πŸ› Fixed

Console β€” Observability

  • Rebuilt Manifest signal declarations through signal.once / broadcast / live in Console bus bind and projectSignalsList so bun run typecheck passes after the callable signal(name, { delivery }) removal.

Runtime

  • SQL insert/update/upsert coerces epoch-ms numbers to Date for timestamp / date columns so fx.clock.now() and seed literals like createdAt: 1 bind on Postgres (was column "created_at" is of type timestamp … but expression is of type integer).
  • Hybrid search: encode LSH buckets as signed int64 for Postgres bigint, insert real[] via {…} text, and store hyperplane seeds without NUL bytes so Bun.SQL + Postgres 15+ accept plane/embedding writes.
  • oke db search-backfill <table> [--batch] opens live SQL (compose env / DATABASE_URL), extracts the Manifest, and runs runSearchBackfill (supports AbortSignal for interrupt + safe re-run).
  • Boot auto-registers _oke_search_embed_* CDC bindings when the Manifest has .embed() columns (bindSearchEmbedFlows via adoptBinding).
  • Built-in Gate auth / plugin Flows no longer need hand-declared effects: {}. When a Manifest is present (oke dev / oke build extract) but a Flow is absent from it (framework code outside the app tree), mintCapabilities stamps an empty least-privilege token automatically β€” fixing **OKE1020** on auth.refresh for advanced Docker scaffolds without reverting to open tokens.
  • Auth / plugin opaque ids (users, accounts, API keys, passkey ceremonies, verifications, tenants, invites, …) use OKID instead of crypto.randomUUID. Session refresh secrets stay crypto.getRandomValues hex (not OKID β€” ids are not credentials).
  • Client typecheck under root lib: ["ESNext"] (no DOM): local ClientCredentials / ClientBodyInit, duck-typed passkey / location, narrowed auth.getToken on live / stream, explicit createClient proxy return types, mutable buildClientDescriptor routes bag, void-input binary call opts in transport tests, and legacy useSession token gate (cookie path is AuthClient-only).
  • oxc-parser is a hard okengine dependency again (no longer an optional peer). Published scaffolds with Docker Compose were dying on **OKE1020** for main.health because Manifest extract could not resolve oxc-parser and boot treated that as β€œno Manifest.” Strict boots now also warn Manifest extract failed β€” … before throwing OKE1020.
  • Threaded EffectKind "embed" through dry-run, signal replay stubs, Console run/effect schemas, Manifest diff EFFECT_KEYS, and Fx test doubles so bun run typecheck is clean after hybrid search. Restored concrete dims on Manifest DeclaredColumn.embed (project defaults still resolve at extract); runtime schema search fails loud when .embed() dims are unresolved. Fixed search-bind to import OkeApp, SearchConfigError override on name, and related compiler/bench typecheck noise.

Dev, Keel & create-oke

  • Notes starter seeds (standard / advanced) use readable calendar Dates (e.g. 2026-01-15T10:00:00.000Z) for createdAt so oke db seed matches field.timestamp() on Postgres.
  • Notes starters (standard / advanced) list oxc-parser so create-oke installs it even against older published okengine builds.
  • oke ai setup / create-oke no longer treats template comment examples of ai.model("smart", …) as an already-configured core β€” that path skipped the ai import and smart binding, leaving only local + summarizeNote and crashing boot with ReferenceError: ai is not defined. A second setup pass now also repairs those incomplete stubs (strip + rewrite smart / local / summarizeNote with the ai import) instead of leaving them.
  • Cloud AI (OpenRouter / OpenAI / …) no longer pins images.ai to llama.cpp. Compose only starts a local AI container for self-hosted providers (llama-cpp Β· ollama Β· vllm Β· sglang). Switching to cloud clears a leftover images.ai pin.
  • oke boot no longer requires OKE_AI_URL for openai-compatible just because Docker is up for Postgres β€” cloud models resolve baseUrl from the provider registry. oke dev also uses compose up --remove-orphans and ignores orphaned exited AI containers when painting element status.
  • oke dev arms BYO OKE_AI_URL + OKE_AI_MODEL readiness watch again after Compose AI recipes were removed (unassigned pendingAiModelWatch left typecheck as never). Vault-gap tests widen process.env after delete so assertions typecheck under strict narrowing.

Docs

  • Fixed trigger item row alignment, badge visibility, height symmetry, ambient auto-cycling (useTick), interactive tabbed contract inspector (in, out, errors, do), and unified domain pipeline examples (orders.*) in FlowTriggers (flow-triggers.tsx).
  • Fixed broken consumers doc example calling users.changed() without a store table receiver.
  • OKE1020 troubleshooting notes missing oxc-parser when Manifest extract fails.

♻️ Changed

Console β€” Store

  • Store browse / query / row detail format *_at / *At epoch-ms cells and Date values as ISO-8601 instead of raw integers.

Dev, Keel & create-oke

  • Notes starters (standard / advanced) expose createdAt / archivedAt (and advanced digest at) as ISO-8601 strings on the HTTP wire (z.iso.datetime()), write new Date(fx.clock.now()) into field.timestamp(), and seed with readable calendar instants.
  • Keel daily-digest mail schema + payload use ISO at; seed T0 is a named calendar anchor (2025-07-31T00:00:00.000Z).

Docs

  • Store seed/upsert samples and Clock digest / cleanup receipts use readable ISO instants on the wire; fx.clock.now() remains epoch-ms for math.
  • Store Β· SQL (elements/store/sql): rewritten to the HTTP page’s depth β€” Smallest Example with response envelope, Progressive Patterns, field / store declare reference, session-handle method tabs (select β†’ upsert), store.resource Define/Mount + option accordions (list grammar, live, subset), schema extras / RLS / relations, seeding, CDC, drivers, and expanded Troubleshooting (including no RQB on fx.store).
  • Store Search (elements/store/search): rewritten to the HTTP page’s depth β€” Smallest Example, Progressive Patterns, field/query reference, two-surface distinction (?search= LIKE vs hybrid query vs store.index), embedding pipeline, fusion, backfill, external indexes, troubleshooting.
  • Two-factor docs: method-locked login challenges, step-up enrollment / method change, Forbidden mid-challenge; OTP docs clarify primary /auth/otp vs second-factor email OTP.

πŸ”’ Security

Runtime

  • Session access JWT verify now allowlists alg: HS256 before HMAC and rejects spoofed algorithms (none, RS256, …) and non-JWS compact shapes (JWE’s 5 parts), closing algorithm-confusion gaps even when the crypto path never switched algorithms.
  • 2FA method lock during active login challenges: the configured method (totp | email_otp) is recorded on the pending challenge; TOTP enrollment / method change / disable while an unresolved challenge exists returns Forbidden (active_2fa_challenge). Closes the July–August 2026 method-switching bypass pattern.
  • TOTP re-enrollment and method change require a successful step-up verification of the current factor; the old method is invalidated only after the new one is confirmed active.
  • Magic-link and email OTP verification reclaim an existing **unverified** email account (CVE-2026-67327 pre-account hijack): revoke all sessions for that principal, clear planted password hashes, mark emailVerified, then issue the passwordless session. Already-verified owners re-auth without a credential purge. Shared helper: completeVerifiedEmailSignIn.
  • Hardened passkey WebAuthn verification against Pass-the-Passkey / Golden Pass-ta-key class failures: require authenticatorData UV (reject UV=false), bind challenges to a ceremony sessionId (≀5m TTL), enforce clientDataJSON.type, and treat non-increasing signCount (when stored β‰  0) as a cloned authenticator β€” log a warning, delete that credential, return reregister_required.