0.12

Every published okengine release, newest first.

all series · 0.13 · 0.11

v0.12.0

✨ Added

Console — Chrome

  • motion (Motion for React) reserved for near-future ui-next animations; import via motion/react.

Console — Observability

  • fx.ask stamps driver-reported input / output tokens onto WideEvent, Parquet, and Console run rows. Observability AI rail shows window totals when present — never a 0-token placeholder.
  • Console **Runs SQL** (POST /console/runs/query, Observability SQL tab) — read-only DuckDB over .oke/runs. Statement guard rejects DDL/DML/external access; isolated session sets enable_external_access=false; 5s timeout; 1000-row cap. Files driver skips re-copy when partition keys are unchanged. PII mask is column-key only (RunsQueryPiiProjectionGap).
  • Fleet registry (oke_instances) — each process heartbeats every 5s (30s TTL) on the existing 1s scheduler. GET /console/instances joins Clock and Journal leases by the unified boot instanceId. Observability shows N alive (unbound is empty, not 0).
  • Console **Observability** (/observability) — health strip (Vault seal/KEK, Store drift, Clock overdue/lease, Signal queue lag, window P95 / error rate), top errors from the persisted runs buffer (opens Trace detail), and a Bklit composed chart (request volume, error count, dual-axis P95). AI cost stays empty until fx.ask writes run telemetry. Instances chip reads GET /console/instances (alive ⇔ TTL).
  • oke dev live Traces bridge: host-app WideEvents POST to Console POST /console/runs/ingest (secret-gated). Console appends into its own runs store → existing feedRun / projectRun PII mask for GET /console/runs and /console/live. Prod stays opt-in (oke({ runs })); the bridge env is set only by oke dev.
  • ui-next trace detail Sheet (shadcn, side=left): row click keeps graph highlight and opens a real breakdown — summary counts from EffectKind + logs, proportional waterfall bars from EffectEntry timestamps/durations (EDGE_STROKE colors), expandable event list, and REQUEST with Manifest method/path plus Shiki-highlighted WideEvent.input. No RESPONSE section (WideEvent has no output field today). GET /console/runs / live projection now include masked input.
  • Console **Kbd** key caps on the command palette, sidebar tooltips, Query run/save, Store grid find/undo/redo, and shortcut sheets. ⌘1⌘5 hop Overview / Flows / Store / Monitoring / Vault; ⌘, opens Settings; ⌘E logs out. Caps show ⌘ on Mac and Ctrl on Windows.
  • Console explorer pages (Overview, Flows, Store, Observability, Vault) share a start-panel collapse / expand control on the inspector header.

Console — Store

  • Call API **PII** matches Store Query: handler responses mask classified fields by default. Toggle includes audited cleartext (revealPii).
  • Console Files is a folder browser, not a key table. Slash-separated keys become folders with breadcrumbs, list/grid views, and an inspector that previews text and images. Operators can upload (including drag-and-drop), download, and delete. Browse returns sizeBytes; POST /console/store/object reads one object; POST /console/store/edit puts patch.body (utf8 / base64).
  • Console Files uploads mint a URL-safe object key (safeFileObjectKey from okengine/store) and keep the original name plus MIME / size in .oke/catalog.json. When the Manifest has a file_objects SQL table, Console upserts that row too. Non-ASCII keys on /edit are rewritten; the old key is deleted. fx.store(files).put is unchanged.
  • Console Store explorer facet bands (SQL / KV / Files / Index) have a show/hide control on each band and an eye menu in the search bar. Hidden bands leave the tree; restore them from the menu. The pick persists in localStorage. Selecting a resource in a hidden facet shows that band again.
  • Console Store table rows show live RLS: emerald ShieldEnergy when enabled, muted ShieldOff when disabled (pg_class.relrowsecurity).
  • Console Store catalog create sheets expose **Advanced** Postgres knobs: Indexes (CONCURRENTLY, INCLUDE, NULLS NOT DISTINCT, WITH), Functions (SECURITY DEFINER, STRICT, PARALLEL, LEAKPROOF, SET search_path, COST / ROWS), Triggers (CONSTRAINT, UPDATE OF, transition tables, TRUNCATE, function args), and Extensions (SCHEMA, VERSION, CASCADEpg_catalog refused).
  • Console Store **Create policy** Advanced pairs RLS with Gate **policy** and **scope** (gate.public, gate.policy, gate.scope) — not the Access Module:Action / role catalog. Read / Write / Both stays the default. Picks stay on Gate — TO public stays on the SQL.
  • Console Store **SQL** and **KV** facet bands open a query console (code icon on the band). SQL runs DML and DDL through POST /console/store/sql (allowWrite on writes, including CREATE / GRANT / EXPLAIN ANALYZE). The workbench has query tabs, session history, a Manifest schema rail (tables + columns), run current / selection (⌘Enter), run all (⌘⇧Enter, sequential, stops on the first error), EXPLAIN / EXPLAIN ANALYZE, gutter play marks, Prettify, a No LIMIT hint, elapsed time, and table / JSON / raw results with CSV copy. A multi-statement script opens a result tab per statement. The SQL editor completes Manifest tables, columns, and keywords as you type (context-aware after FROM / SELECT / WHERE, plus CREATE / ALTER / DROP / EXPLAIN); KV completes list / get / set / delete / ttl and namespaces. Schema collapses to a right-edge strip; results collapse to the status bar (Run expands them again). KV namespaces expand to inferred value fields (same rail as SQL columns). Double-click a tab to rename; Save keeps named queries in localStorage (History → Saved). Tabs persist across sessions. KV set(key, value, ttl?) writes through POST /console/store/edit (same script Pending Changes emits). delete and ttl match the fx.store handle (ttlMs); word and call forms work for every command. oke_console stays refused for raw SQL.
  • Console SQL query console toolbar can **include PII**. Default stays masked; turning PII on sends revealPii: true on POST /console/store/sql and re-runs the last read (writes stay untouched). Results meta shows PII masked or PII visible.
  • Console KV query console has the same **Prettify** control as SQL. It rewrites list / get / set / delete / ttl to call form and indents set JSON.
  • Console SQL query console can **view data as a Gate** — three cards (Operator, Public, As). Operator bypasses RLS. Public and As set oke.gate on postgres / pglite. As picks a user (via their matching policy) or a Manifest policy gate. Policies read current_setting('oke.gate', true). Memory SQL accepts the pick but does not apply session GUCs.
  • Console Store SQL band **Schema** opens a visualizer of Manifest tables, columns, and relations — declared .references() plus inferred *_id columns (search, auto layout, copy as SQL, smart Colorize, PK / FK / unique icons, cardinality icons for many-to-one / one-to-one / many-to-many / self; click a related table to dim the rest).
  • Console Store SQL table browse can **insert a row** from the grid toolbar (Insert data). Empty fields stay NULL; id defaults to a UUID. Omit id on POST /console/store/edit to INSERT (patch.id required).
  • Console Store **Indexes** catalog can **Create index** — the same form-and-preview sheet as RLS Policies (templates, table / columns / method, plus a free highlighted SQL editor), then CREATE INDEX through POST /console/store/sql (allowWrite). Refuses anything that is not CREATE INDEX.
  • Console Store **Functions** catalog can **New function** — the same form-and-preview sheet as RLS Policies / Triggers (templates, name / args / returns / language, plus a free highlighted SQL editor), then CREATE FUNCTION through POST /console/store/sql (allowWrite). Refuses anything that is not CREATE FUNCTION.
  • Console Store SQL folders add **Triggers** under each SQL store. Browse uses live pg_trigger when the engine has it; otherwise an empty list. **New trigger** uses the same form-and-preview sheet as RLS Policies (templates, table / timing / events, plus a free highlighted SQL editor), then runs CREATE TRIGGER through POST /console/store/sql (allowWrite).
  • Console Store tree adds **Expand all / Collapse all** next to search, on each facet band (scoped to that facet's folders), and on each store folder. Facet bands start open; store folders and SQL Tables start collapsed. Selecting a resource re-opens its facet, not the folder. Search still expands matching folders.
  • Console Store can list the **oke_console auth schema** beside app SQL (oke_operators, sessions, roles, API keys, identities) when OKE_CONSOLE_AUTH_STORE=1. Hidden by default. Browse is read-only; credential hashes stay masked until audited reveal. Edit / delete / raw SQL are refused so operator-plane rows never join public.
  • Console Store SQL folders add **Indexes**, **Functions**, and **Extensions** under each SQL store (app db and oke_console). Browse uses live pg_* when the engine has it; otherwise Manifest primary-key / unique indexes. Extensions list built-in contrib packs with an enable / disable toggle (CREATE / DROP EXTENSION). A Library sheet searches and adds external packs (TimescaleDB, PostGIS, pg_cron, DuckDB, plv8, FDWs, …) by name, alias, or category. Memory keeps the catalog in-process. The SQL editor does not complete these as tables.
  • Console Store SQL folders add **RLS Policies** (__policies). Browse lists pg_policies. Create policy reviews CREATE POLICY (and optional ENABLE ROW LEVEL SECURITY) before it runs. **Templates** opens a flush rail beside the form (SELECT / INSERT / UPDATE / DELETE / ALL, owner, oke.gate, joins, restrictive extra check). oke_console stays read-only.
  • Console Store Extensions can **upgrade** to the newest packaged version (ALTER EXTENSION … UPDATE). The name chip shows the current version and an Upgrade action (pgvector 0.8.00.8.6). Names link to the project page or Postgres docs.
  • Console Store replica-lag chip follows the newest touching run from the live runs buffer (same /console/live merge as Traces) and uses the Traces duration cool→hot palette (emerald → yellow → rose). Falls back to the store-list snapshot when the buffer has no lag.
  • Console Store **PII chip** toggles masking for every classified column on the current browse page. Off (amber) sends audited revealPii: true on QUERY /console/store/query; on (sky) remasks. Switching tables remasks.
  • Console Store browse **Import / Export** in the grid toolbar. Export downloads the current page (or checked rows) as CSV or JSON. Import parses CSV/TSV/JSON, matches rows by id/key already on the page, and stages writable cells as uncommitted changes (PII [redacted] values are skipped). Does not insert new rows — there is still no /console/store/add endpoint.
  • Console Store JSON cells (KV value, Index meta, and JSON strings) show a trailing **Open as table** icon. It opens a sheet with a flattened field table plus a full-height JSON editor. On writable KV/SQL cells, table fields and JSON source both edit in place and stage the reconstructed object as an uncommitted change.
  • Console Store KV browse adds **TTL** and **size** columns. TTL is remaining time from the driver (PTTL on redis; intended TTL on memory) and is editable in the grid (30m, 1h, or empty to clear). Size is the UTF-8 JSON byte length of the value, and updates as you stage edits. **Add key** upserts via POST /console/store/edit (no /console/store/add endpoint). Value-only edits now preserve remaining TTL instead of wiping it.
  • **Console ui-next Store page (v1)** — read-first browse at /store: facet tree, schema, masked SQL row browser with audited reveal, KV/files/index browsers with honest “not PII-classified / no SQL-grade masking” copy, and reverse readers/writers linking to Units/Flows (no edit/delete/SQL console).
  • **Console ui-next Store page (v2)** — browse is now a virtualized data grid (TanStack Table + Virtual, Base UI chrome) with column sort, find-in-page (honest “increase Limit to search more rows” copy), and safe mutations:
  • Edit (SQL/KV) runs dry-run preview → typed EDIT + reason in production; PII-masked cells require audited reveal before edit and the client strips any [redacted] placeholder from the patch.
  • Delete (all four facets) requires typed DELETE + reason in production.
  • Server applyEdit rejects a patch value equal to [redacted] on a classified PII column so the mask can never overwrite real data.
  • No SQL Insert UI (no /console/store/add endpoint); KV “add” is edit/set.
  • No server-side column WHERE filters yet — v1 find/sort are client-side on the fetched page only.
  • Console Store SQL band **Performance** view — slow queries, cache hit rate, and live lock blocking from pg_stat_statements / pg_locks (QUERY /console/store/sql/stats and /locks). Structured PgStatStatementsNotPreloaded / Unsupported / NotCreated instead of a generic 500. Index Advisor is opt-in: Enable when pg_available_extensions lists index_advisor, otherwise a CTA to pin oke-postgres-advisor:18-alpine. Suggest copies CREATE INDEX DDL and does not create indexes.
  • Local postgres / pgvector recipes preload pg_stat_statements at postmaster start. Timescale keeps timescaledb first (timescaledb,pg_stat_statements). supabase/postgres and Yugabyte commands are unchanged. Opt-in oke-postgres-advisor:18-alpine emits Dockerfile.postgres-advisor (hypopg + index_advisor). Default postgres:18-alpine is unchanged.
  • ui-next seed now fills all four Store facets with real data (previously schema-only): SQL bookings 5 rows / shipments 3 rows (with a PII email column), KV holds 4 keys, Files uploads 3 objects (one non-ASCII key for warnings), Index docs 4 vectors. Seeded via seedUiNextStoreData in both the Vite dev plugin and the Playwright fixture.
  • fx.store(index).list(limit?) returns stored documents (id + meta, no embeddings) on every index driver. Console Index browse uses it so an empty search lists the catalog.
  • Store query performance: preload vs CREATE EXTENSION vs unsupported on Postgres / Timescale / Supabase Docker / Neon / Supabase / Yugabyte / Cockroach pages. Index Advisor opt-in image documented on the Postgres recipe.
  • Store KV **Performance** (QUERY /console/store/kv/stats) — Redis-wire INFO / COMMANDSTATS / SLOWLOG / LATENCY on the KV band. memory returns KvStatsUnsupported. INFO is instance-wide (StoreKvStatsServerWideGap). SLOWLOG args collapse until reveal (StoreKvStatsSlowlogArgsGap). No MONITOR, no invented hot-keys.

Console — Vault

  • Console Vault **Add** (+) creates a secret or config from the operator plane as well as from vault.secret / vault.config in source. Metadata lands in .oke/vault-contracts.json; the value uses the same write path as Set. A review dialog (name + fingerprint) pauses before the write — same as set / rotate. Rows show a console chip until the name is declared in the Manifest.
  • Console Vault is a security instrument, not a filter-and-empty-state. Deep search (is:unset, is:blast, from:.env.local, reader:, fp:) ANDs over name, fingerprint, readers, and winner. Posture chips and a scan board surface unset, blast, shared, dormant, and overdue contracts. Resolution is a lock-path. Security (verify chain, rotate master, fingerprint export, CLI copy) lives in one sheet. Values stay write-only.
  • Console **Vault** page (/vault): fingerprints-only list + backend status, set / rotate via typed confirm, and master rotation through POST /console/vault/rotate-master (one batch, remaining honest, ROTATE_MASTER + reason). Any operator in the same process may continue; overlapping batches return VaultRotateBusy. Generated master key is shown once and never logged. Audit verify is GET /console/vault/audit/verify (ok, brokenAt, reason, row). Backup stays on the CLI. The Console never accepts a master key in the HTTP body.

Console — Flows & traces

  • Boot wires drivers.runs (files in dev/prod at .oke/runs, memory in test). oke replay and host recording share that root. create-oke templates install @duckdb/node-api. runs.keep deletes old Parquet partitions (7d in dev, 30d in prod). Console listRuns unions live ingest with disk so Traces survive a Console restart.
  • ui-next Flows split-view is bidirectionally interactive: clicking a flow node filters the Traces list (flow = X advanced clause), clicking a signal node filters to runs whose flow emits or consumes that signal, and clicking the canvas clears the filter (removable chip in the filter row).
  • ui-next Trace detail sheet supports sticky effect focus — click a waterfall bar, overview segment, or event row to pin emphasis (click again to release).
  • ui-next Replay is now visible: a Motion playhead sweeps the waterfall while bars grow as it crosses them, the hero duration counts up in sync, and the Flow graph pulses along the causal chain. All motion respects reduced-motion settings.
  • ui-next Traces pane parity: contextual formatDuration (μs / ms / s), status row tint + trigger icons (HTTP / Signal / Clock), persistent selected accent, hover Replay + Copy run ID, and All/Errors + duration-threshold filters over the scoped runs list. POST /console/traces/replay now re-invokes through runReplay (same path as oke replay --request-id), not a log-only stub.
  • ui-next trace detail Sheet surfaces the **Gate** element: summary chip from run.gates, plus a Gates section with Manifest kind/description (e.g. member · policy · Signed-in member on support.triage).
  • ui-next Request section is a protocol frame: method-colored rail, Body with Fields/Raw toggle (typed key·value rows + per-field copy), byte size, and line-numbered Raw JSON.
  • WideEvent / Console runs project optional **output** (flow return value), PII-masked like input. ui-next trace sheet shows an Output protocol frame; seeded skyport runs include realistic outputs (failures omit them).
  • ui-next Traces duration filter uses shadcn Base UI Select with cool→hot colored dots on each threshold (Any / >10ms…>5s), matching row duration tones.
  • ui-next Traces **Advanced** filtering: progressive-disclosure dimension query (flow = X AND cache = miss AND duration > 1s) with presets, chips, and expression editor — same language as Runs (§9.11), client-side on the scoped list.
  • ui-next eight-element HugeIcons vocabulary (ELEMENT_ICONS) aligned with site Lucide; Traces trigger icons and Flow graph nodes share Flow / Signal / Store / Clock / Gate / Vault / Channel / AI glyphs.
  • bun run dev:console-next:seeded (OKE_CONSOLE_NEXT_SEEDED=1) boots the same Console kernel + skyport Manifest + seeded WideEvent chain as the Playwright ui-next fixture, so opening http://127.0.0.1:6537 shows a real Flows graph and Traces (click → highlight). Terminal prints URL, claim code, and a one-line seed summary.

Console — Units & Call API

  • dev:console-next:seed Units tree is a full work-management HTTP surface: CRUD on tasks, comments, projects, documents, attachments, spaces, tags, goals, members, views, and forms, plus custom routes (archive, assign, complete, follow, QUERY search, PUT drafts, HEAD health). Call API binds every HTTP flow.
  • ui-next Units ↔ Flows connector: /flows?flow=<id> seeds the graph/Traces filter and fitView; Units contract header has **Open in graph**. Recent activity strip shows real buffered call count / error rate for the selected flow (honest empty when the Console runs buffer has nothing in-window). Units subscribes to useRuns + /console/live like Flows.
  • ui-next Units **Platform failure modes**: derived only from this flow's Gates
  • request schema with HTTP-encoding truth (Unauthorized 401 · Forbidden 403 · RateLimited 429 · ValidationError 422) — not OKE#### codes and not Call API chrome's default-400 quirk. Declared Flow errors stay a separate tier.
  • Console POST /console/flows/invoke executes the target flow on a bound host via invoke-as (assumed identity scopes) — no more stub echo / inv_* responses. Fail-closed when the host adapter is unbound. Optional pathParams; response includes status / failure / runId when the host provides them. Kernel execute accepts trustedInvoke for console-trusted principal injection outside env: "test".
  • ui-next **Units** page (/units): Manifest flows grouped by unit, contract panel (request/response schema rows, typed errors, gates, effects), and session-authenticated Call API wired to real invoke-as.

Console — Auth & shell

  • Console claim **Generate** mints a first-operator password that meets Console policy (12+ upper, lower, number, special) and copies it to the clipboard.
  • oke console claim-code prints the first-admin claim mirrored to .oke/claim-code (mode 0600) on Console boot while setup is open; cleared after a successful claim. Same code still prints once to the boot log.
  • bun run dev:console-next boots an ephemeral Console kernel on :6533 beside Vite and prints the claim code in the same terminal (also mirrored to .oke/claim-code). Uses bunx --bun vite so the Console graph runs under Bun (not Node).
  • ui-next operator login when setup is closed: Email + Password (TanStack Form + Zod + shadcn Field) posts to real POST /console/session/login, stores oke_console_at on success, and surfaces AuthFailed / AuthRateLimited errors. Same ConsoleChrome shell as claim. Gate extended in test:console:setup-ui-next.
  • ui-next authenticated shell (Phase 3): TanStack Router (/ pre-auth, /overview · /flows · /store guarded shell). Claim and login success navigate to /overview. Sidebar-07 layout collapsed by default, OKE logo header, Overview/Flows/Store nav with honest Empty placeholders. Unauthenticated shell visits redirect to /. Gate: test:console:setup-ui-next.
  • Parallel Console SPA scaffold at src/console/ui-next/ (React + Vite + shadcn/Base UI + TanStack Form/Query + HugeIcons) with a real first-admin claim page wired to /console/setup/status and /console/setup/claim. Existing src/console/ui/ is unchanged; cutover is not yet. Gate: bun run test:console:setup-ui-next.
  • ui-next shell chrome: OKE wordmark + light/dark/system theme toggle (official shadcn Vite ThemeProvider, oke-console-theme storage, no next-themes).
  • Console sidebar **Fast** opens a ⌘K command palette (navigate, theme, settings, logout). **Settings** is a dialog with operator identity and the theme toggle. **Logout** posts /console/session/logout and returns to sign-in.

Runtime

  • http.resource(path, ops) chains .gate(...) and .live() like http.get. Gates apply to every verb; live marks list and get.
  • gate.all(...members) reuses a gate chain. .gate(write) flattens the handle (and plain arrays) left to right. The compiler expands .gate(write) and .gate(...WRITE) onto flow.gates.
  • .gate.public is the unauthenticated sentinel — same as .gate(gate.public), without importing gate.
  • Handwritten HTTP lists prefer the Stripe envelope (out is the item array, fx.json.withQuery(rows, input)). Extra keys auto-eq except path id. fx.json.with(page) stays for an already-built pager. Any other declared out is still valid.
  • Official managed vault providers now include Azure Key Vault, GCP Secret Manager, Doppler, and 1Password Connect alongside AWS Secrets Manager. Set drivers.vault to "managed" and OKE_VAULT_PROVIDER to the id. Cloud SDKs stay optional peers; Doppler and 1Password use fetch.
  • http.query() — RFC 10008 safe, idempotent HTTP trigger that still carries a JSON body. Content-Type: application/json is required (missing → 400 InvalidQuery; other types → 415 UnsupportedMediaType). Invalid JSON is 400 with no sniffing. QUERY responses and 405s that allow QUERY advertise Accept-Query: "application/json". CORS default methods include QUERY; CSRF treats QUERY as safe (like GET). The client always sends a JSON body on QUERY ({} when only path params remain).
  • Browser GET (Accept prefers text/html) paints the JSON envelope in traces chrome — flush h-10 strips, hairline /60, status + handler latency
  • cache (hit / miss / none), a right-rail Routes tree (static GET links; POST and :param listed), line numbers, copy, Pretty / Raw (compact stays on the same page). curl, Accept: application/json, ?format=json, and /_/ · /_oke/ stay JSON.
  • Console operator reads store/query, gates/simulate, gates/powers, access/effective, and channels/preview now bind QUERY. store/preview stays POST (audited dry-run).

Dev, Keel & create-oke

  • create-oke standard / advanced ship a Vite 8 web/ SPA. Vite owns index.html and proxies /notes · /health · /_oke to the app. bun run web after oke dev.
  • Keel lists speak PostgREST v16 read grammar: col=eq|neq|gt|gte|lt|lte|like|ilike|in|is|match|imatch, not., like(any).{…}, nested or= / and= / not.and, order=col.desc.nullslast, select=id,alias:col. store.resource now accepts not., is.not_null, quoted in.(), and nested or/and groups.
  • bun run dev:keel:reset tears down the keel Compose stack (oke docker clean --yes) and deletes .oke/, .env.local, and generated Docker extras so the next dev:keel is a first boot.
  • defineSeed({ name, description }) labels this app's seed (template or example). oke dev asks Seed keel (Featured Harbor GA story + volume + vault stubs)? and .oke/state.json stores that id — a different name re-prompts. Not a global seeded flag.
  • examples/keel is a work-management OKE app (not a create-oke template) for oke dev against Compose — Postgres, PgDog, Redis, RustFS, Mailpit, Meilisearch, and llama.cpp. Featured Harbor GA task chain, stub GitHub/Slack ingest, bun run dev:keel, then oke db seed.
  • Keel pins images.pgdog so Compose puts PgDog in front of Postgres. DATABASE_URL is the pooler (:6432); OKE_STORE_SQL_URL stays the direct host.
  • create-oke asks **Add a reverse proxy…?** (Caddy / Traefik / nginx / No) and persists proxy in ~/.oke/create-defaults.json. Flags: --proxy <id> / --no-proxy.
  • nginx image recipe (nginx:1.27-alpine) — generated nginx.conf reverse proxy on :80; companion docs under Recipes → nginx.
  • playwright.ui-next.config.ts always records trace + screenshot + video; after bun run test:console:setup-ui-next, bun run test:console:setup-ui-next:report opens the HTML timeline report.
  • oke-images skill (.agents/skills/oke-images/) — probe registries and bump Compose pins in catalog, recipes, templates, Keel, and docs without inventing tags.

Docs

  • Docs site machine surfaces for agents: spec-compliant /llms.txt (absolute links, curated sections, Optional rest), /llms.json, /llms-full.txt with teaching-figure fallbacks, /llms/agents (the AGENTS.md contract), /robots.txt (allow-all including named AI crawlers), and /sitemap.xml. Per-page markdown is /llms.mdx/docs/⟨slug⟩; /content.md and .md still resolve. HTML docs pages advertise rel="alternate" type="text/markdown".

💥 Breaking Changes

  • Global password policy defaults are now minLength **8** with uppercase, lowercase, number, and special character required (DEFAULT_PASSWORD_POLICY.requireSpecial). Previous defaults were minLength 12 with letter + number only. Override via gate.auth.passwordPolicy / createOperator({ passwordPolicy }). The special-character option is named requireSpecial (failure reason requireSpecial); do not use requireSymbol on password policies.
  • Stack env is project .env.local only. Vault resolution is driver → process.env.env.local → (optional) dev-fallback. oke docker merges stack keys into .env.local; compose env_file is ../.env.local. COMPOSE_ENV_REL is .env.local. The .env.docker file and resolution source are gone.
  • Console routes are now /overview (graph + Traces), /flows (explorer), /store, and /vault. Unknown paths (including /units) are 404 — no legacy rewrite. Dev scripts are dev:console / :seed / :fresh (the -next suffix is gone).

♻️ Changed

Console — Chrome

  • Explorer folder rows (db, Tables, unit folders) use the same text-xs as leaf rows — the group token had no size and read larger.
  • Signal uses Hugeicons InternetAntenna03 everywhere (Units bands, live flags, traces, graph) — was the slashed Radio01.
  • Console tab chrome uses the O mark favicon, title **okengine Console**, and an operator description meta (was a generic icon and "oke Console"). Module routes prefix the page name (Overview · okengine Console).
  • Console data tables drop the muted header fill and use the same hairline / hover as explorers: Store browse, query results, files list, JSON inspect, and Vault fingerprints. Store browse restyles the row checkbox at the table, not the shared control.
  • Console sidebar: the graph/traces page is **Overview** (/overview); the Manifest catalog is **Flows** (/flows). /units redirects to /flows. Sign-in lands on Overview. Legacy ?next=/units rewrites to /flows. The Flows explorer search placeholder is **Search flows…** (was units).
  • Schema type badges use one hue per type (string teal, integer blue); rose stays on risk pills.
  • Console sheets share one flat language: full-bleed fields (no boxed inputs), text toggles instead of chips, and a flush Cancel | action footer. Create policy, index, function, trigger, insert, KV add, edit, confirm, pending changes, and the extension library all use it.
  • Console theme toggle is strip tokens (ink when active, icon-only when idle) — no sliding pill, no muted chip. Same control in Settings.
  • ui-next theme tokens match SACP web zinc (tuned dark card/muted + chart/sidebar).

Console — Observability

  • Observability SQL Run is a stretch strip token; the PII gap note is hairline text. KPI labels use tracking 0.08em and /60 hairlines. Error rows open the local Trace sheet instead of navigating to Overview. Leftover monitoring-* slots are observability-*.
  • Console explorers share the Overview traces language: flush rows, bare tinted icons, tabular counts, and a full-height selection rail. Flows, Store, Vault, and Observability lists plus detail headers drop boxed wells. Advanced on Flows is an icon control like Traces.
  • Console inspector identity (Vault / Store / Units) matches the Observability Query / Metrics header: one h-8 strip. Title, kind, and env / copy sit on one centered baseline; risk, PII, Set, and Rotate stay full-height strip tokens. Vault posture and Units activity use the same stretch bar.
  • Console explorer tokens encode traces chrome: stretch toolbars, EXPLORER_STRIP_* bars, flat icon buttons (no bordered wells). Search, filters, Query, Call, Vault, and Monitoring strips use those tokens — selected ink only.
  • Console Monitoring Metrics / SQL tabs and the Query header are flush strips (no pill tabs, no blur header). Sidebar module icons are flush in the rail — hover fill, no chip. The brand cell and explorer search / identity / command headers share h-10 — between the old 32px strip and a full 48px rail square.
  • Console sidebar order is Overview / Flows / Store / Monitoring / Vault. Monitoring uses the chart-analysis mark.
  • Console Monitoring is now **Observability**. Canonical route is /observability; /monitoring keeps a search-preserving redirect (bookmarks and ?next=). Sidebar, command palette, and digit 4 point at the new path.

Console — Store

  • Store KV uses Hugeicons Braces on the band (same { } mark as site Store docs). Leaves use a job glyph — drafts, reminders, view prefs, webhooks — instead of the same key on every row.
  • Store Index / KV leaves skip the folder wrap when a store has one child with the same name (commentscomments). Files already did this for a single bucket.
  • Console Store Query PII uses the view / view-off glyph. Gate keeps the shield so the two toolbar controls no longer share an icon. The query command strip matches Call API: full-height, square tokens (Gate / PII / Schema / Run). Gate As picker drops the User/Policy tray and rounded rows for flush list chrome.
  • Console Gate picker (Store Query and Call API) is a flush strip: Operator / Public / As keep the access diagrams; Operator and Public show a one-line hint; As still opens the user/policy list.
  • Console Query results toolbar matches the command strip: h-8 flush tokens, hairline /60, no boxed icon wells.
  • Console index browse Search / topK lives on the grid toolbar (one strip — no second search row). Sidebar nav idle icons sit at 40% ink; the active module is a solid accent chip.
  • fx.store(index).driverId is the configured driver before first I/O (was a gated function, so seed treated Meilisearch as memory and wrote one vector blob). Keel dev pins meilisearch. Index browse promotes title / identifier columns.
  • Console Index browse is a search box, not a vector probe. Type a phrase to rank documents by id and stored meta (Meilisearch uses full-text q). Paste 1, 0, 0 to run an ANN probe. Opening the index lists documents immediately.
  • Console Overview graph is a radial hub, not a spaghetti of every flow × effect. OKE sits at the center; the eight elements orbit it; each element's kinds sit on a middle ring (Store SQL/KV/Files/Index, Gate policy/scope/rate/flag, Channel email/SMS/WA/Push, and the rest); units sit on the outer ring with live heat from Traces. Hover a unit to light the elements it touches. Click a unit or flow for a 1-hop neighborhood; click an element disc to fan its resources. Map breadcrumb returns to the hub. Opening Overview runs the orchestra: random notes from the traces ledger land as new rows and light that request's path on the hub (paused while a run or neighborhood is open).
  • Console Files treats the **bucket** as the inspectable unit. A singleton store.files(name, { buckets: [name] }) is one tree leaf (no attachments → attachments). The list payload may include driverId (memory / fs / s3) so the tree and header can show where bytes live. Click a file to open a right-side sheet (same chrome as SQL / KV row detail) so the folder list stays full width. The sheet previews images, PDF, video, audio, and text (pretty JSON, CSV table). The toolbar is path + find + view + upload + delete + refresh.
  • Console Files upload shows the original name (Unicode OK) and a generated ASCII key. The browser lists and searches by original name. Existing non-ASCII objects keep the non_ascii_key warning until they are re-uploaded.
  • Console Store **Create policy** is easier to scan: table and behavior share a row, FOR is a compact command strip, Gate / Rows are chaptered, and the SQL preview stays pinned above Create. USING and WITH CHECK appear only for the commands Postgres accepts.
  • Console Store **Create index**, **New function**, and **New trigger** match that layout: compact template chips, paired fields, chaptered Options, and a pinned editable SQL dock above Create. Choice rows (Language, Method, Timing, FOR) keep the label on the same line as the chips so they do not read as empty field headers.
  • Console Store SQL catalog folders use sql:db/indexes (and functions / triggers / extensions / policies) instead of the __indexes reserved prefix. Query still accepts the old __ names.
  • Console Store **Extension library** Install reviews required extensions and the CREATE EXTENSION SQL (requires first) before enabling a pack.
  • Console Store **Extension library** is a marketplace sheet: featured Timescale / Cron / PostGIS cards, search + category select, and an installed badge — not a flat list.
  • ui-next Store browse adopts a single toolbar + row-detail Sheet layout (SACP-style chrome): Refresh, find-in-results, sort indicator, Writers/Readers popover, tenant, page size, and row count on one row; column headers carry PK/type glyphs from the Manifest; double-click a row for Fields/JSON detail with the existing audited Reveal, edit, and typed-confirm Delete. No Insert / Export / pagination arrows — those have no real backend endpoints. Seed bookings gain an Arabic note so mixed RTL/LTR cells render without breaking column alignment.
  • ui-next Store resource pane is now an edge-to-edge explorer workbench: compact identity chrome (status chips on the right, PII copy on the chip tooltip), a command strip with growing find, a spreadsheet grid (PK / PII / numeric headers, cell focus ring, compact audited reveal), and an IDE-style status bar. Instructional banners are gone.
  • ui-next Store grid is now the beUI editable Table: inline cell edit (commit on blur/Enter), row-handle delete (typed confirm, no Insert), selection, sort, resize, and reorder. PII-masked cells still use audited Reveal; JSON/RTL/numeric cells keep their formatters. Find, undo/redo, column visibility, and the status bar stay on the command strip.
  • ui-next Store grid stages edits locally: dirty cells fill brown with tan text; a selected range is navy with a 2px primary outline on the head cell. Changes opens a Pending Changes sheet (Visual diffs + SQL, Clear All / Commit All, ⌘S). Click selects a cell, click again or type to edit, drag to multi-select (paste/type fills). The row-detail Sheet is gone from browse — edits stay in the grid until Commit All.
  • Console Store Query / KV performance headers use the shared identity strip: one baseline for title, ref, and actions. The Index Advisor pin note lives in the limitation banner, not the h-10 chrome.
  • Console Store Schema find is the explorer search field (flush, no magnifying-glass overlay). Table count stays tabular and unclipped.
  • Console Store SQL / KV Query identity uses the shared header strip: one baseline for title, ref, and statement hint. Store / tenant pickers are flush tokens, not pills.

Console — Vault

  • Console Vault list rows are two lines: description + risk on the first, env name and readers on the second. Healthy rows drop the trailing set/config word. Band hints live on the section title.
  • Console Vault detail is one path: identity, a next-action banner with the verb (Set / Rotate) when something is wrong, a posture strip (from / read / readers / blast), then the lock path as a first-hit-wins spine. Pick a layer to copy its fill command in the row. Fingerprints and readers stay flush lists. Shared and in-flight runs sit on the posture strip / blast banner — no Advanced dump. One Set or Rotate on the page, not two.
  • Console Vault set / rotate drop the typed SET / ROTATE phrase. Pick a reason chip (scheduled, leak, provider, …) or **other** and type a note. Submit opens a review dialog (name, fingerprint, reason) — Cancel aborts; Confirm is the write. Add uses the same dialog. Rotate-master still types ROTATE_MASTER.
  • The env vault driver lock-path matches vault/managed: driver → process.env.env.local → (optional) dev-fallback. Console writes still persist to .env.local.
  • Console Vault lock-path paints the winning layer emerald (same hit tone as the docs figure). Winner / last-read / readers / blast briefing rows carry icons. The first lock-path step is always driver; its chip shows built-in, managed · aws, or simulate (env driver) on the same line.
  • Console Vault lock-path simulate / driver-kind chip uses emerald ink on the won wash (not muted-foreground) so contrast holds in dark mode.
  • Console Vault list bands (Secrets / Config) collapse like Store and Units. Row wells use posture color and icon (overdue clock, blast alert, config source) instead of one gray key.
  • Console Vault lists declared contracts only — undeclared process.env keys no longer appear as secrets. Seeded keel vault is five secrets plus four public config values (origin, API, docs, workspace) with winners across driver / process.env / .env.local. Overdue chips say overdue; hover explains the rotate window (Last read older than rotate 90d — never-read counts). Secrets that must not rotate declare rotate: "never" (omit is the same); Console shows no rotate.

Console — Flows & traces

  • Overview orchestra (random minted traces) runs only in dev:console:seed. Live oke dev Traces stay operation-based — Clock, HTTP, Call API — not cloned ledger notes.
  • Console lookback and facet tokens are flat text (15m / 1h / 24h / 7d, Vault posture, Flows filters) — no muted segment well. Selected lookback fills the strip (bg-muted/70). Filter tokens hover-fill the strip (Traces All / Errors / duration, Call dock, schema toolbar, sheet tabs).
  • Console overview Store spoke shows only SQL / KV / Cache / Files / Index. Named KV namespaces (drafts, reminders, view-prefs, webhooks) fan when Store is focused.
  • Console Traces list row no longer shows Replay — that action lives on the trace detail sheet.
  • Console Traces list row shows cache status before duration: flash for hit, slashed flash for miss, muted unavailable for not applicable (run.cache). The detail sheet repeats the same mark next to the trigger kind.
  • Console Traces filters drop the pill well: All / Errors are flat text toggles and duration is a borderless select. Advanced visualizes applied clauses (trigger = signal) instead of a raw query dump; presets toggle those clauses. SelectTrigger now accepts flat.
  • ui-next Traces filter chrome: title, Advanced (icon + count), and live status share one header; All/Errors + duration sit on a single non-wrapping row with the duration select filling leftover width — no more wrap that stranded Advanced on a second line.
  • ui-next Flow graph visual craft: per-kind HugeIcons + accents (Flow/Store/Signal/AI), color-coded bezier edges for reads/writes/emits/calls, @dagrejs/dagre LR layout, selection glow + desaturated dim, tighter unit-group bounds, and a pannable MiniMap.
  • oke dev request lines append the WideEvent / run id after the timestamp so a Console GET /console/vault line can be pasted into Traces or oke replay --request-id.
  • Console Trace / Flows Gates heading matches Waterfall: title and count sit together on the strip, not justify-between.

Console — Units & Call API

  • Console Units tree lists HTTP flows by method: GET, POST, QUERY, PATCH/PUT, DELETE (then name). Was alphabetical, so delete sat above get.
  • Call API Response status uses the same traces cache glyph as the Traces list (CacheGlyph: sky flash / amber flash-off / muted unavailable) beside 200, then duration. Reveal-PII invokes skip auto-cache and do not invent a hit.
  • Console sidebar hops restore the last Flows / Units / Store / Vault URL (selected trace, flow, resource, contract) instead of wiping the module back to its empty landing.
  • Seeded Console Call API runs against the same Store as browse. issues.list returns rows, issues.create inserts, attachments.delete returns the deleted object. A leftover :id path token is NotFound, not a fake 200. Path fields prefill keel seed ids.
  • Seeded Console list Call API takes query + pagination: q, teamKey, limit, offset, cursor, orderBy, order. The response includes items, count, total, limit, offset, and nextCursor.
  • Console Call API Response has an expand control that opens the full JSON in a wide sheet (copy included) so long list payloads are readable.
  • Console Call API body fields sit on a container grid that drops from five columns to one as the dock narrows.
  • Console Traces toolbar uses the same explorer search as Units / Store / Vault (Search traces…) instead of a title. The query matches flow, unit, trigger, cache, error, and run id.
  • Units explorer bands and folders start collapsed (search still expands matches).
  • Console Units inspector is a vertical workbench: contract briefing above, Call API docked below (always visible). Request/Response sit side by side; identity, Fields/Raw, Reset, and Call live on the dock toolbar — no more scrolling past a long contract to invoke.
  • Console Flows contract no longer lists derived Platform failure modes (401/403/422/429 from gates + schema). Declared Flow errors stay. Gates remain in their own section.
  • Console Flows, Units, Store, and Vault share one explorer language: 28/72 split, h-8 search toolbar, tinted band headers, sky selection rail, sticky identity header, and the same Empty pane. Vault search and posture chips live in the left explorer (not a page-wide bar).
  • ui-next Units tree: trigger bands (HTTP, Signal, …) are bordered, clearly separated sections with chevron + tinted kind-icon headers; unit folders also show chevrons and nest flows under a guide line — both levels collapse/expand (auto-reopen when the selection is inside). Trigger glyphs are now distinct per kind (API / radio / calendar / timer / store / function) with matching icon wells in Traces.
  • ui-next Units Call API is trigger-aware: HTTP keeps method/path + body; call-only keeps flow.in with a bypasses-caller note and Manifest callers from effects.calls; cron/every prefer lease-gated /console/clock/run-now when a Manifest clock soft-joins, otherwise honest empty-input invoke fallback; signal keeps handler invoke with copy that it does not test bus delivery physics.
  • fx.ask stamps RunTelemetry.promptVersion and adds cost only when the driver supplies usage.cost greater than zero. Token counts persist on the ask journal. oke dev attaches the host AI runtime so Call API asks reach GET /console/ai. Child-process HTTP asks still have a separate journal (no ingest bridge).
  • Console Call API Response (and Body / Path params chapters) use the shared explorer strip: 0.08em heading, ink status, flush JSON rail — no padded well or status chip.
  • Console Call API expanded Response sheet header is the same strip: stretch copy / close, hairline before close, no absolute icon-sm well or pr-12 dodge.

Console — Auth & shell

  • Sign-in prefills dev@oke.dev only on standalone dev:console / :seed. oke dev and production leave email and password empty.
  • Console Sign in / Create admin expanding-arrow tile uses primary ink, not sky.
  • Console Sign in / first-admin claim is a docked lock: wordmark sits on the plate, calibration ticks on the corners, two-column instrument fields, page-ink tile on the key. The submit key sits below the plate, not inside it.
  • Console claim / sign-in lock column is max-w-md (was max-w-sm) so the first-admin plate has room for the password meter and generate control.
  • Setup / sign-in is a gate, not an inspector: OKE wordmark in open air, LED eyebrow + display title, underline ledger fields, ink key. The page foot stays traces (brand, theme tokens, version) — no boxed tray, no pill theme well.
  • Console claim / sign-in drops the nested muted tray. The form is a lock ledger (uppercase labels, underline fields, display title); setup state stays an LED eyebrow, not a strip chip.
  • Console Sign in / Create admin is a sharp expanding-arrow key (primary bar inverted per theme, sky tile, near-black dotted trail) — beUI motion, Console rail color, no lime pill.
  • dev:console-next / :seed boot a fixed operator (dev@oke.dev / Okengine123!) so restarts skip claim; login form prefills in Vite serve. dev:console-next:fresh / :fresh:seed keep first-admin claim open. Renamed dev:console-next:seeded:seed.
  • Console first-operator claim keeps a stricter minLength **12** with the same character classes (CONSOLE_PASSWORD_POLICY), shared by the claim flow, ui-next meter/Zod, and setup docs.
  • ui-next password strength bar uses a red → amber → lime → emerald ladder (theme primary washed out mid-progress in dark mode).
  • ui-next authenticated sidebar stays always icon-collapsed on desktop (no expand / rail / header trigger); mobile sheet trigger unchanged.
  • Console sidebar footer drops the operator avatar. Icon actions are Fast (command palette), Settings, and Logout.
  • ui-next authenticated shell drops the inset top header (page title breadcrumb); content uses the full inset area.
  • Console is the ui-next SPA. oke dev / oke start serve src/console/ui-next/dist/. Initial-load budget is 700 kB gzip (no legacy panel-* split).
  • Access, Manifest Diff, Plugins, and standalone Runs are not in this Console yet — named backlog, not silently dropped. Backend projections remain.
  • oke dev Notices and 4xx/5xx request follow-ups use the Claim house block: a colored ◇ Notice / ◇ 401 chip on its own row, then the body — yellow for warnings, red for 5xx. No dim line.

Runtime

  • The files runs driver no longer uses a deleted tmpdir: default root is .oke/runs, all() reads every Parquet file (not just this process's catalog), and the memory driver opens DuckDB only when query() runs.
  • fx.json.with accepts a { data, meta } page (fx.json.with(page)) as well as the two-arg form. Flow out stays the item array — do not put the page object on out.
  • List meta.next / meta.prev are the next request ({ cursor }), not flags. The typed client walks with page.next() or for await (const page of api.notes.list({ limit: 20 })) — no .pages(), no if (mode), no hasNext. meta.next / meta.prev are typed { cursor } bags for TanStack pageParam. Offset and keyset tokens share ?cursor=. hasNext / nextCursor / hasNextPage / ClientCall.pages are gone (unreleased).

Dev, Keel & create-oke

  • Keel Files is one keel bucket (was attachments). Seed lays out workspace folders — attachments, documents, avatars, projects, exports, forms — so Console browse matches the app.
  • Keel and Console seed now declare four store.index facets — tasks, documents, comments, and projects — and fill each from featured + volume rows (was tasks only).
  • Keel oke db seed (dev) initializes the built-in vault and writes the keel stubs plus minted stack URLs (Postgres / Redis / S3 / Meilisearch / Mailpit / AI) so /vault looks like production. .env.local keeps OKE_VAULT_MASTER_KEY and PORT — other apps still leave Vault empty.
  • examples/keel now picks Signal delivery per job: comments, projects, forms, and goals emit once + broadcast + live (notify / search / late-subscriber feed). Tasks add task-changed broadcast; task-assigned is live optional.
  • Keel Compose now starts llama.cpp so all eight elements are live. drivers.ai is openai-compatible in dev/prod (mock in test); the hero shows openai-compatible · granite3.3:2b instead of .
  • examples/keel and Console ui-next seed are work management (spaces, goals, projects, sections, tasks, forms, views) with first-class project_manager / developer roles — not a Linear issue tracker. Featured walkable id is ENG-12. Seed volume is ~500 tasks across SQL, KV, files, and index.
  • Keel scheduled flows drop the repeated unit from the name: drafts.expire, overdue.watch, recurring.spawn, goals.rollup, digest.daily (was drafts.expire-drafts, …).
  • Keel list responses put the item array in data and pagination in meta (Stripe envelope). out is z.array(Item), not { items, count }. create-oke Notes notes.list uses the same envelope. Store / Flow docs teach it as the preferred handwritten list, not a requirement.
  • examples/keel flow in / out schemas now come from drizzle-zod (createSelectSchema / insert / update on generated tables) instead of hand-copied z.object column lists.
  • S3 files (RustFS / MinIO) create the configured bucket on first open when S3_ENDPOINT is set, so oke db seed and uploads no longer fail with The specified bucket does not exist.
  • examples/keel oke db seed now writes the same lived-in Linear story as Console ui-next seed — featured ENG-184 chain plus ~500 generated issues, comments, labels, drafts, attachments, and search index documents.
  • ui-next seeded mode (dev:console-next:seed) is a Linear-shaped **keel** workspace: github.ingest → issues.create → notify.onIssue, CycleClosed failure, live issues.list, cycle rollover, Triage Intelligence, and draft TTL — all eight elements plus CDC, ~14 SQL tables (teams through customer_requests), KV drafts, file attachments, and issue search. Eight featured rows + 72 ops (~80 traces). Store browse defaults to 500 rows so the 500+ issues backlog (plus comments, labels, drafts, attachments) fills the grid. sql:db also lists the app Gate auth + oke schema generate system tables (oke_identities, sessions, roles, crons, vault stubs) — distinct from the Console oke_console operator folder.
  • Default Compose image pins: RustFS 1.0.0-rc.2, Mailpit v1.30.7, PgDog v0.1.53, Meilisearch v1.53, llama.cpp server-b10450, Ollama 0.32.13, vLLM v0.27.1, SGLang v0.5.17-runtime, Traefik v3.7, nginx 1.31-alpine. Floating tags (postgres:18-alpine, redis:8-alpine, caddy:2-alpine) stay.

Docs

  • /llms.txt is a curated llmstxt.org index instead of the raw Fumadocs nav dump. Onboard AI copies /llms.txt plus /llms/agents on the current origin. The documented Vault curl no longer 404s.
  • Landing CollapseDiagram shows the zoo and okengine rings side by side on one shared step (no tab switch).
  • AI docs: fx.ask resolves capability pins name@version against the declared prompt; a mismatched pin is ai: unknown prompt.

🔥 Removed

  • store.resource({ unit }) — unit comes from flow("notes.list") and .adopt({ notes }), not a resource option.
  • Legacy src/console/ui/ Console SPA (15 panel-* chunks, Vite :6534).
  • Console Traces duration-threshold select (Any / >10ms…>5s). Status (All / Errors) and Advanced (duration > 100ms) remain.

🐛 Fixed

Console — Chrome

  • Console shortcut caps use ⌘ on Mac and Ctrl on Windows. Detection reads Client Hints / userAgent, not only navigator.platform.
  • Sidebar Logout hover is destructive ink + wash. Tooltip and palette show ⌘E / Ctrl+E.
  • Console icon-rail selection is readable: idle icons sit at 30% ink, the active chip uses a stronger --sidebar-accent, and hover no longer clears the selected fill.
  • Console Flow and Store schema MiniMaps were blank: graph nodes only set style.width / style.height, and xyflow MiniMap skips user nodes without top-level width / height.

Console — Observability

  • Console GET /console/runs no longer nests each list response back into the runs store (console.runs.list output elided on record; prior list polls filtered from the projection). Live/poll fallbacks were doubling payload size every tick and OOMing the ui-next kernel (~GB RSS).

Console — Store

  • Console index browse keeps focus while typing. Search no longer sits inside a tooltip trigger, the grid stays mounted across keystrokes, and the query waits 280ms of quiet.
  • Console Store browse no longer shows classified emails in cleartext. ownerEmail / owner_email (and the same JS/SQL spelling split) mask as [redacted] unless the operator enables Include PII.
  • Store Query editors paint SQL and KV with their own token colors (keywords / commands, strings, keys, numbers, comments) instead of a single gray overlay. KV is no longer highlighted as bash.
  • Console Store KV browse on a dedicated namespace (store.kv("drafts")) lists root keys (ENG-184) instead of looking for drafts:*. Extract stamps namespaces so Overview Store resources include KV.
  • Console Units Call no longer paints a thrown host error as 200 + response: null. A 500 envelope or OkeError (including OKE1006 undeclared secret) shows as a failure. Extract now binds vault.config so fx.vault.get(publicAppUrl) declares PUBLIC_APP_URL, and list flows can return the seeded rows Store SQL already shows.
  • Console Units Call **Invoke as** uses the same Operator / Public / As Gate cards as Store Query. Operator bypasses the flow's gate chain; Public is anonymous; As picks a user or policy.
  • Console Store schema graph infers camelCase FKs (teamId, issueId, parentId) the same as *_id, so keel tables draw relation edges instead of a single unlinked column.
  • Console SQL query editor applies Shiki token colors with inline theme ink (github-light / github-dark) so SELECT / FROM are not a flat grey overlay.
  • Console Units Call identity picker uses the same card menu as Store Query Gate (name, email, scopes) instead of a plain select.
  • oke dev Console Call API and Store SQL now use the live host app (compose Postgres / Redis), not the empty Manifest memory sandbox. Invoke-as no longer returns InvokeDenied: host invoke not configured.
  • Console SQL query console **Gate** menu no longer crashes on open (MenuGroupContext — label now sits inside DropdownMenuGroup).
  • Console Store RLS policy rows are editable in the grid (ALTER POLICY for roles / USING / WITH CHECK). Creating a policy with RLS on now flips the table shield to emerald.
  • Console Store explorer shows the RLS shield only on SQL tables (pg_class.relrowsecurity). KV, files, and index children no longer get a muted "RLS disabled" badge.
  • Console Store SQL console no longer fails default SELECT * … LIMIT 50; on the memory driver — trailing semicolons are stripped before parse.
  • Console Store Pending Changes **KV tab** shows set(key, value, ttl?) instead of a fake SQL UPDATE. Visual diff is unchanged. SQL tables still get the SQL tab.
  • Console Store KV namespaces now have unique effect refs (kv:drafts vs kv:triage-snooze). Selecting one no longer highlights both, and browse lists only that namespace's keys.
  • ui-next Store cell edit no longer draws a focus ring; pending brown fill covers the whole cell. Escape or clicking empty space clears the cell range.
  • Console storeEdit / storeDelete SQL DML through sql.raw now uses exec (the memory driver has no generic UPDATE/DELETE on query), so ui-next Commit All actually writes rows instead of returning InternalError.
  • Console Manifest StoreRuntime now derives SQL classify maps from tables.*.columns PII/sensitive tags (and table.column keys on store.classifications), so browse masking matches list piiColumns without a hand-registered classify map. Store query/edit/delete/sql paths also bind the panel-lazy runtime (previously only list did).
  • Console Store browse of a Meilisearch index no longer fails with InternalError after the index already exists. Open is idempotent (GET then create; index_already_exists / HTTP 409 is success). Browse errors show the driver message, not a bare code.

Console — Vault

  • Console Vault **Set** on Simulated env no longer returns VaultNotFound. The panel boots with gaps so the first write can land in .env.local.
  • Console Vault lock-path no longer shows simulate under oke dev when drivers.vault.dev is "vault". The Console was not given oke.config, so it fell back to the env driver. oke dev now passes the loaded config; serveConsole loads oke.config.ts from cwd when it is omitted.

Console — Flows & traces

  • Tier-1 cache hits record the real computed:… lookup on the effect ledger. Trace Waterfall shows that cache read instead of "No effects recorded". Miss runs still show the store reads that actually ran.
  • Console Trace request / response body fills leftover sheet height. Raw JSON is no longer capped at 14rem with empty space below. The sheet is max-w-2xl (was max-w-xl) so the payload has more room.
  • Console Traces / Runs no longer 500 after a failed login sits next to a successful run. All-null error_code Parquet batches were JSON; Unauthorized was VARCHAR — DuckDB refused the union.
  • Console Overview no longer paints Cache as a fifth Store type. Store kinds are sql · kv · files · index. Cache is a KV namespace (and HTTP read cache), not a facet.
  • Console Overview element discs are name-only: no N live caption and no live-heat pulse. Center edge handles stay invisible. Hubs are 56px and show the two-letter lattice symbol (Fl · Sg · St · Ck · Gt · Vt · Ch · Ai). Hover still names the element.
  • Console Traces Advanced clause and preset labels use stronger ink so they stay readable on the dark pane (no muted-on-muted greys).
  • Console Traces list always shows relative time in the right column. Failed runs keep the rail / dot; hover still carries the error code.
  • Console Flows graph keeps node cards (ships) above effect ribbons. Parent-group edges no longer inherit a child z-index that paints lines over store / signal / AI targets.
  • /flows renders the graph + Traces page and /units renders the explorer — the path names now match the pages.
  • HTTP API-key Bearer now authenticates through onAuth. WideEvent principal is the key id and dimensions.api_key is stamped. Session JWTs stay claims.sub with no key dimension. Forged / revoked / expired keys are 401.

Console — Units & Call API

  • Call API Fields / Raw no longer draws a second hairline under the dock toolbar (the toggle sat in its own strip).
  • fx.ask now converts Zod / shorthand out to JSON Schema (validate + response_format). Mock fills that shape instead of { ok, echo }, so Call API documents.summarize returns a summary instead of generic Unavailable. Docker openai-compatible fails loud without OKE_AI_URL. Concurrent /console/ai no longer 500s on a duplicate DuckDB runs view.
  • Call API Response no longer flashes cleartext then remasks, or drops the 200 chip on a PII toggle. Hide PII remasks in place; reveal refetches. The JSON viewer never paints a stale highlight.
  • Call API **PII** now opens the host store session with cleartext when Include PII is on, and skips auto-cache so a prior masked list is not reused. Classified columns the handler reads (ownerEmail) were already [redacted] at the driver.
  • bun run dev:keel:reset writes a fresh .env.local from .env.example (PUBLIC_APP_URL and the other vault / app defaults). The next dev:keel regenerates stack passwords. Keel now passes KV / index stores, vault configs, and clocks into oke() so Call API and KV Query resolve after a wipe.
  • Overview Store spoke always shows **Cache** (engine fx.cache — not a Call API / trace) and fans declared KV namespaces (drafts, triage-snooze, webhooks) so keel does not hide them behind a Store click.
  • Call API **PII** now renders on the toolbar. The panel imported runs-pii from a path Vite could not resolve, so :6533 kept the last bundle without the control.
  • Tables with a name column (teams, labels, cycles, …) no longer fail Call API with OKE1001 sql:db. The kernel now reads tableName so the capability matches extracted sql:<table>.
  • Console Traces now lists Call API invokes (issues.list and other host flows). The in-process attach used by oke dev posts WideEvents to the same ingest bridge as the app child, so they sit next to clock ticks like drafts.expire.
  • Console Units Call Response shows the handler output JSON on success. Invoke-as also unwraps fx.json and HTTP { data } envelopes when execute left output empty.
  • Console Units Call path-param fields show the route token as a placeholder (:id) and stamp the path on the Path params chapter.
  • Traces no longer show 0μs for a handler that finished in the same millisecond. Duration uses performance.now() when the app clock did not tick. Call API shows that handler time (same clock as Traces) and labels the browser round-trip as rtt.

Console — Auth & shell

  • Command palette search mark is size-3.5, same as explorer row icons — it no longer fills the 40px strip.
  • oke dev keeps the first-admin claim code on the live board (paste URL + oke console claim-code). The code is TTY-only — never returned from GET /console/setup/status. After surfaces bind, the TTY reprints one Ready board (elements, Docker, claim, notices, Backend / Console / MCP) so mid-boot db-push lines and health ticks cannot tear the claim box. The bun --hot child no longer clears the screen on schema reload. The pane drops after the first operator.
  • Console setup chrome footer no longer draws hairline rules against the theme toggle. Brand sits left, theme center, version right.
  • Console Sign in after an expired session returns to the module you were on (/store, /units, /flows plus search) instead of always opening Flows. ?next= only accepts those three paths.
  • First-admin claim/login no longer 500 with ReadableStream has already been used when a stale oke_console_at cookie (or Bearer) is present — public-flow onRequest skips re-wrapping a body already consumed by parseValidate.
  • Console fields stay transparent when the browser autofills. html uses Tailwind scheme-light / scheme-dark; autofill ink follows --foreground with no UA wash.
  • First-admin claim no longer flashes Sign in before Overview. Setup closes the instant the operator exists; the gate keeps the Created plate and uses the new session instead of swapping to login.

Runtime

  • fx.ask with a versioned prompt handle (document-summary@1) resolves the bare prompt id. Call API documents.summarize no longer returns Unavailable ai: unknown prompt.
  • After oke keel reset, Console Call API no longer mocks fx.ask when OKE_AI_URL is set. Traces also show fail(code, { message }) on the run (Unavailable was a code with no reason).
  • Clock every jobs no longer re-enter on the 1s scheduler tick. The slot (lastRunAt) is claimed before the handler, stacked ticks are skipped, and a named clock covers its interval so keel does not register both watch-overdue and 15m.
  • OKE1005 no longer fires when a flow asks a prompt by name and the Manifest stamped effects.asks as name@version (compiler pin). documents.summarizedocument-summary matches document-summary@1. Distinct pins still deny.
  • Console Gates list no longer 500s on apps that use gate.public. Reconstructing the Manifest used gate.policy("public"), which is reserved.
  • Boot mints one instanceId (inst-<uuid>) for Clock, Journal, and the fleet registry. They no longer mint independently with different prefixes.
  • Read-only flows cache automatically from inferred or ledgered reads — no cache: "30s" and no fx.cache. The first GET is a miss; the next identical GET is a hit. cache: false opts out; a duration string adds a TTL. Writes invalidate matching keys.
  • GET /_oke/client.json wraps the runtime route map as { routes } so oke dev can regenerate oke-client.d.ts. Chrome GET /json/version probes are silent on Backend as well as MCP.
  • Clock traces like drafts.expire no longer fail with a bare OkeError and no message. fx.store(kv).delete(key) now extracts kv:<namespace> (not kv:key), ttlMs is a read, and thrown OkeErrors record as OKE1002 plus the cause.
  • store.schema.table with a name column no longer throws Unable to resolve table name from value on insert, select, or Drizzle emit.
  • Wrong-method hits on a registered path return **405** with Allow listing bound methods (was a generic 404). CORS preflight still answers first. Raw Console ingest 405s now include Allow: POST.
  • Password policy special-character rule is canonical as requireSpecial on both DEFAULT_PASSWORD_POLICY and CONSOLE_PASSWORD_POLICY, with regression tests that a password missing only a special is rejected and that ui-next’s 5 checklist criteria match server validation.
  • Kernel edge and Store-only oke() no longer statically import PostgREST listPage, i18n catalogs, http.resource, or auto-cache. Those load through computed import.meta.require when the feature actually runs, so unused graphs stay under budget.

Dev, Keel & create-oke

  • Keel oke db seed no longer fails vault boot on empty OKE_CONSOLE_SECRET / MEILI_MASTER_KEY / OPENAI_API_KEY. Those contracts (and the other stack configs) now have dev fallbacks so the app can boot before seed writes the store. Compose OKE_STORE_INDEX_KEY still maps to MEILI_MASTER_KEY.
  • oke db seed no longer crashes tallying Meilisearch upsert (undefined is not an object (evaluating 'result.status')). Index upserts return void; only SQL { status } is counted.
  • Keel reset no longer pins OKE_AI_URL=http://127.0.0.1:8080/v1. oke dev writes the published llama.cpp port (:23xxx).
  • oke dev / bun run dev:keel hot-reloads Console UI from source. Vite attaches on an okengine checkout so ui-next edits no longer need bun run build.
  • oke dev under Compose no longer refuses keel CRUD with OKE1008. bindCrud stamps sql:<table> on each verb; extract expands the same. Authors do not declare effects at the call site.
  • A fresh oke dev hero now shows the effective driver map (signal Redis, clock Postgres, files S3, channel SMTP) even when oke.config.ts only pins overrides. dev:keel:reset SIGTERMs leftover listeners on :6530 / :6533 / :6535. Chrome inspector probes on MCP (GET /, /json/version) no longer paint as 404s.
  • Keel oke db seed no longer inserts sections before projects (sections_project_id FK). Essential seed is spaces / members / tags; sections land with projects in the volume step.
  • oke dev no longer crashes when an app binds http.query (RFC 10008). Bun.serve native routes reject QUERY; those verbs stay on the fetch fallback. An invalid route table retries fetch-only — Bun's HTML-bundling example is not printed.
  • bun run dev:keel no longer dies with OKE1008 on cycles.list. Extract expands bindNamedTableCrud into unit-prefixed CRUD flows so effects are inferred, not hand-declared.
  • create-oke **reuse previous settings** no longer re-asks locales / PgDog / proxy — saved answers from ~/.oke/create-defaults.json apply directly (CLI flags still override).
  • ui-next tsconfig no longer typechecks the Vite Console kernel plugin (SPA stays DOM-only); root tsconfig covers vite.config.ts + the kernel plugin.
  • Typecheck for tests/console/setup-ui-next.spec.ts via a DOM-scoped tests/console/tsconfig.ui-next.json (root stays ESNext-only for kernel/server tests).
  • bun run build no longer warns that Console chunks exceed 500 kB. Highlighting loads five grammars through the JS engine (no Oniguruma WASM / unused C++ bundle), and Overview / Flows / Store / Vault are lazy route chunks.
  • oke dev no longer writes a label-only Compose app service when Traefik is pinned. That stub had no image or build, so docker compose up failed with service "app" has neither an image nor a build context. Laptop oke dev stays infra-only; Traefik labels still apply when oke docker includes app.
  • oke dev no longer attaches Console Vite HMR to the create-oke file: stage (~/.oke/create-oke/okengine). That copy has ui-next source but is not the monorepo, so the browser requested /src/features/flows/flows-page.tsx and failed. Scaffolded apps serve ui-next/dist like a published install. Vite attach stays on for the okengine checkout (workspaces in package.json).
  • create-oke templates and the local okengine stage list @duckdb/node-api in trustedDependencies so Bun runs its native postinstall. Console run history falls back to in-process events when DuckDB is missing instead of crashing the kernel.
  • oke db push missing_hints now prints the unresolved statements instead of only the status line.

Docs

  • Docs Signal and AI figures no longer ask Motion to interpolate oklch / lab theme tokens (stroke / fill stay attributes; Motion animates opacity and position only).
  • Docs GET /sw.js is no longer a 404. A leftover service worker on localhost:3000 was still asking for the script; the site now serves an unregistering worker and drops the registration.

🔒 Security

Console — Store

  • Console Store hides oke_console (operators, sessions, credential hashes) unless OKE_CONSOLE_AUTH_STORE=1. Query is refused when the flag is off.
  • Console security gate **5c**: default QUERY /console/store/query on a table with PII-classified columns never returns unmasked values; POST /console/store/reveal returns cleartext and leaves an audited console.store.reveal Runs log (operatorId, ref, child, id, column) — same suite class as gate **5b** host-ingest masking.
  • Console security gate **5e**: default POST /console/store/sql masks classified columns; revealPii: true returns cleartext and writes an audited console.store.sql.reveal log (operatorId, ref).
  • POST /console/store/sql asGate must be public or a declared policy Gate (rate gates refused). The pick is audited as console.store.sql.asGate (operatorId, ref, gate).
  • Store SQL performance query text is a named limitation StoreSqlStatsQueryTextGap — engine-native fingerprints, not Store browse masking. Live pg_stat_activity.query is collapsed until revealPii: true, which writes console.store.sql.stats.reveal. Documented in security.md §10.4.
  • Store KV SLOWLOG args (keys and values) stay collapsed until revealPii: true, which writes console.store.kv.stats.reveal (operator, ref). Named limitation StoreKvStatsSlowlogArgsGap.

Console — Flows & traces

  • Host → Console runs ingest never returns WideEvent bodies; operator reads stay on the masked projectRun path (adversarial PII gate covered).

Console — Units & Call API

  • Console invoke-as adversarial coverage: assumed identity A never executes with identity B's scopes; host gates enforce the assumed principal.

Console — Auth & shell

  • Console login ?next= is allow-listed to /overview, /flows, /store, /vault, and /observability (plus their search). /monitoring rewrites to /observability. Other values (including /units) are dropped so an expired session cannot be an open redirect.

Runtime

  • Host HTTP API-key authentication stamps principal as the bare key id (and dimensions.api_key) so Access per-key matching is real when a request is key-authenticated.