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.