# Changelog 0.6

## v0.6.1 — 2026-08-01

### ✨ Added

- Channel drivers on [sently](https://sently.omqkhafi.dev) 1.0 — `sndr` (email), `taqnyat` / `msegat` / `unifonic` (SMS); `wa-cloud`, `webpush`, and `fcm` wrap sently transports. Boot resolves `resend` / `sndr` / `taqnyat` / `msegat` / `unifonic` from env. SMS fallback chains use sently `FallbackTransport` / `RetryTransport`. Re-exports `toChannelSendResult`, `parseSndrWebhook`, `parseUnifonicWebhook`, and `toDeliveryEvent` from `okengine/channel`.

- `scripts/webpush-interop.ts` — manual Channel → Web Push check against a real browser subscription (reuse sently’s subscribe page; prints push-service HTTP status / headers / body). Default VAPID subject uses `@example.com` (Apple rejects `@oke.local` / `@localhost` with `403 BadJwtToken`).

- Root `.env.example` (and create-oke template) covering Channel, Store, Vault, AI, and Console keys — copy to `.env.local`.

### ♻️ Changed

- Dependency `sently` bumped to `1.0.0`.

- `webpush` driver sends through sently `createPushSender` wrapping `WebPushTransport` (same Channel surface; push sender pipeline for hooks).

- Root `README.md` redesigned with [shieldcn](https://shieldcn.dev/) — adaptive glow header, shadcn-styled npm / JSR / license / Bun / stars / CI badges, and scaffold commands aligned to `create-oke`’s `standard` template (dropped the stale `--template hello`).

- Local CI test suite is leaner by default: Docker live suites need `OKE_TEST_DOCKER=1`, Ollama live needs `OKE_TEST_OLLAMA_URL` or `OKE_TEST_OLLAMA_DOCKER=1` (no auto-probe on `:11434`), create-oke `oke dev` boot needs `CREATE_OKE_DEV_INTEGRATION=1`, and npm pack / JSR dry-run run under `bun run gate` via `PUBLISH_GATE=1`.

- Site homepage motion — proof strip and budgets tree read `budgets.json`, Flow simulator for the one-law band, settle reveals, spotlights, and reduced-motion gates across the landing bands.

- Landing polish — hero fact chips share the law-chip shell (border / card), with a TypeScript brand mark in `#3178C6` and mono icons for Backend / version; Manifest wiring diagram with packet flow, and icons on proof / budget / surface chips.

- Hero element lattice sits lower and larger, with the lit-cell accent as a 1px rule on the cell’s bottom edge and a roomier docs footer; the collapse diagram’s idle feed lights a small multi-element operation each beat instead of a single concern.

- Landing budgets panel: four AGENTS caps as headline metrics (measured of limit, % used), then `okengine` and `okengine/plugins` as baselines with leaf entrypoints / per-plugin rows collapsed by default (Base UI Collapsible); plugins grouped auth · security · ops · perf — rounded timings (`36 ms`, `< 1 ms`) instead of false-precision decimals; Features panel keeps the shared card chrome.

- CI budgets measure each official `okengine/plugins` named module (regression group `plugins` in `budgets.json` / `BUDGETS.md`), not only the plugins barrel.

- One-law band: full-width claim, then two equal peer panels — a vertical Flow path (matching CodePanel chrome) beside the starter snippet, instead of stacking the diagram under the heading.

- Element feature cards drop the decorative dot lattice and drifting placeholder icons — content and preview chips only.

- Local `bun run ci` runs Budgets first so the cold-start probe is not inflated by Format/Lint/Typecheck/Tests heating the machine.

### 🐛 Fixed

- `bun run budgets` writes oxfmt-aligned `BUDGETS.md` tables, so Format no longer fails after every budgets refresh.

## v0.6.0 — 2026-08-01

### ✨ Added

- AI tool-calling through the same path as `fx.call` — `fx.ask(prompt, input, { tools: [flowRef, …] })` and `fx.run(agent)` share one model-driven tool loop; each tool is a Flow (capability, Manifest `calls`, Runs portal). No silent extra authority for the model.

- Real `fx.stream` — Ollama NDJSON and `openai-compatible` SSE; cancellation reuses the ambient `AbortSignal` from `fx.all` / `fx.race` (one channel).

- `AI_RATE_PRESETS` / `aiRateGate("ask" | "agent" | "embed")` — Gate rate presets for expensive AI edges (defaults 20 / 10 / 60 per minute, `keyBy: "user"`). Cost caps stay on prompt/agent `budget` decls.

- Optional `headers` on AI open options (e.g. OpenRouter `HTTP-Referer` / `X-Title`) — still one `openai-compatible` driver, not per-vendor ids.

- Live Ollama tool-calling integration test (gated ask → real tool → ledger portal; skip-visible without a reachable Ollama).

- `defineLocale` / `fx.t` — register EN/AR (or any) message catalogs; `fx.t` resolves locale → `i18n.default` → key. Request locale comes from `Accept-Language` (matched against `oke.config` `i18n.locales`). `fx.locale` exposes the active tag; channel `fx.send` defaults to it. Starter ships `src/locales/en.ts` + `ar.ts`.

- ICU MessageFormat for `fx.t` (FormatJS `intl-messageformat`) — interpolation, cardinal/ordinal plurals, `select` / `selectordinal`, and rich-text tags (`<tag>…</tag>` with function values).

- Type-safe message keys — `defineMessages`, `MessagesFor<typeof en>`, and `declare module "okengine" { interface Register { messages: typeof en } }` so `fx.t` autocompletes keys and rejects typos at compile time.

- Docs — [i18n](/docs/reference/i18n) reference page (ICU catalogs, typed keys, locale matching, built-in failure messages vs Channel `{{field}}`).

- `magicLink` / `emailOtp` Channel catalogs include Arabic bodies alongside English (`locales: ["en", "ar"]`).

- Built-in EN/AR ICU catalogs for typed failures (`errors.*`) and OKE codes (`oke.*.cause` / `oke.*.fix`). `fail` / `fx.fail` attach a localized `error.message` from the active request locale; thrown `OkeError` localizes cause and fix. Override via `defineLocale`; explicit `{ message }` wins.

- `ollama` AI driver — thin native `POST /api/chat` client for any pulled model (`OKE_AI_MODEL` / `ai.model`); documented local-dev default `qwen3.5:9b` (balanced starting point, fully overridable; Apple Silicon can use `qwen3.5:9b-mlx`). Base URL `http://127.0.0.1:11434` via `OKE_AI_URL` / `OLLAMA_HOST`. Unreachable servers throw `OllamaUnavailableError` — never a silent mock fallback.

- Ollama Docker recipe (`images.ai: "ollama/ollama"`) — pulls the configured model, health-checks, writes `OKE_AI_URL`. Boot resolves `drivers.ai` through a shared `aiDriverFor` switch (same class as store.index).

- Live Ollama integration test (real completion; skips visibly without a reachable Ollama / explicit Docker opt-in).

- `magicLink` / `emailOtp` deliver challenges via Channel (`fx.send` + `auth-magic-link` / `auth-email-otp` templates and English catalog bodies). `exposeDevToken` / `exposeDevOtp` stay for local DX without SMTP. `phoneNumber` SMS delivery remains deferred.

- Plugin API `.channelCatalog(catalog)` — merge template bodies into boot Channel catalog (parallel to `.channelTemplate`).

- Mailpit integration tests prove real SMTP capture of magic-link token/link and email OTP (skip with a visible warn when Docker is unavailable).

- `username({ usernamePolicy, passwordPolicy })` — tunable min/max length, charset, letter/number/symbol requirements, and reserved names on sign-up. Policy failures return `AuthFailed` with `reason: "username_policy"` / `"password_policy"` and a `reasons` array (taken usernames stay enumeration-safe as `invalid_credentials`).

- `username` default reserved blocklist (`DEFAULT_RESERVED_USERNAMES`) — `admin` / `root` / `api` / `auth` / `anonymous` and peers. `reserved: []` opts out; a custom list replaces (does not merge).

- `usernamePolicy.extraAllowedChars` — append characters to the default (or `allowedChars`) charset without replacing the whole set.

- `usernamePolicy.extraReserved` — append names to the default (or `reserved`) blocklist without replacing it.

- `usernamePolicy` shape rules — `mustStartWithLetter`, `forbidEdgeSymbols` (default on), `forbidConsecutiveSymbols` (default on).

### ♻️ Changed

- Ollama documented local-dev default model is `qwen3.5:9b` (was `qwen3:8b`; same as `qwen3.5:latest` on the [Ollama library](https://ollama.com/library/qwen3.5)). On Apple Silicon, set `OKE_AI_MODEL=qwen3.5:9b-mlx` for the MLX build. Docker recipe / compose control use the non-MLX tag.

- `openai-compatible` AI driver is the shared chat/completions client for OpenAI, Groq, Together, OpenRouter, vLLM, LM Studio, and Ollama `/v1` — configure via `baseUrl` + `apiKey` + `model`. apiKey is required only for the default OpenAI cloud base; custom bases may omit it. Native `ollama` remains the first-class local path.

- Native `ollama` driver adds tools + streaming (`stream: true` NDJSON) on `/api/chat` (still fail-loud; never silent mock fallback).

- Effect inference: `fx.ask(…, { tools: […] })` with static Flow refs adds them to Manifest `effects.calls`.

- Rebased export/driver budgets after AI depth (tools, stream, rate presets) and related Unreleased work; refreshed `budgets.json` / `BUDGETS.md`.

- Rebased the Store-only `oke()` gzip graph baseline (41.4 kB → 50 kB) after shared `fx` growth (stream + i18n).

- Rebased the `plugins` export budget after Channel delivery wiring (13.84 kB → 14.77 kB), and refreshed the published budgets snapshot.

- Rebased the `plugins` export budget after username policy wiring (14.77 kB → 15.54 kB), and refreshed the published budgets snapshot.

- Rebased the `plugins` export budget after username Gate-auth parity (15.54 kB → 15.97 kB), and refreshed the published budgets snapshot.

- `username()` sign-up inherits `gate.auth.passwordPolicy`, `password` hash knobs, and `breachCheck` (same as email/password Gate auth). Explicit plugin opts still override for that method only.

### 🔒 Security

- `Redacted` values in `fx.ask` / stream prompts are masked with `[redacted]` before they reach any provider (same class as `fx.log`).

### 🐛 Fixed

- `smtp` channel driver passes sently's `BunAdapter` so real SMTP (Mailpit / providers) works under Bun — previously failed with "No socket adapter configured".

- Mailpit auth-delivery tests use real `test.skip` when Docker is unavailable (never an empty pass).
