Skip to content

v1.0.0-RC6

Latest

Choose a tag to compare

@fwbrasil fwbrasil released this 05 Aug 00:28

v1.0.0-RC6 ships Kyo's own SQL module. kyo-sql pairs raw SQL with a typed DSL that mirrors SQL syntax, and underneath there is no JDBC: the drivers speak the Postgres and MySQL wire protocols directly on kyo's async network stack 🚀

kyo-sql is built the way the whole release is built: implementations written once, in shared source, that reach every platform. kyo-net lands as the transport and TLS stack that kyo-http, kyo-jsonrpc, and kyo-sql now share. Its transport and TLS are C libraries driven through kyo-ffi (shipped in RC5, gaining a Wasm backend this cycle), so the same implementations run on JVM, JS, Native, and Wasm. The I/O backend is chosen by the operating system, io_uring with an epoll fallback on Linux and kqueue on macOS and BSD, and TLS goes through a BoringSSL-first engine. Consolidating on one implementation also removed dependencies: JDBC never enters the tree, io.aeron and upickle leave kyo-aeron, and kyo-i18n and kyo-markdown ship pure Scala where the standard answer is a JavaScript-only runtime or a JVM-only library.

Thirteen new modules are published and two are removed. Almost all of the new work is in application-level modules rather than in the effect system itself. One note on the four-platform claims: Wasm cross-builds and is tested in CI, but Wasm artifacts are not published to Maven Central (see Breaking changes).

A Node.js process now runs kyo-net's io_uring transport and BoringSSL TLS through koffi, the same accelerated stack as the JVM, Native, and Wasm. Kyo also now has out-of-the-box GraalVM native-image support.

Kyo now requires JDK 25. The build's default compilation target moved from -release 17 to -release 25, so nearly every published artifact now declares the Java it actually needs. RC5's artifacts already could not run on JDK 17: they linked successfully and then failed at runtime. kyo-scheduler (with its -zio / -pekko / -finagle integrations) and the kyo-compat-* bindings still target Java 17. Breaking changes carries the full list of exceptions.

New Features

New modules

  • kyo-sql (README), with kyo-sql-postgres (README) and kyo-sql-mysql (README), is Kyo's SQL module. Raw sql"..." and typed queries are one surface that composes in both directions, and the typed DSL mirrors SQL syntax rather than translating collection operations: what you write keeps the shape of the statement it renders to. Typed queries can be generated at compile time through ordinary Scala 3 inlining, with no annotation or build step, and the SQL string lands in the artifact as a constant. JDBC never appears: each driver implements its server's wire protocol directly on kyo-net, a statement suspends a fiber instead of blocking a carrier thread, and one set of shared sources, protocols included, compiles for all four platforms, which is what makes a SQL client outside the JVM possible for Kyo at all. (by @fwbrasil in #1833)

  • kyo-net (README) is the transport underneath kyo-http, kyo-jsonrpc, and kyo-sql: TCP, Unix-domain sockets, stdio, and TLS over one completion-based I/O driver. New this cycle, the accelerated transport and the BoringSSL TLS engine run on JS and Wasm too, driven through koffi, a Node FFI, where both previously fell back to Node's own net/tls, a different implementation with different semantics. JVM and Native behavior is unchanged. BoringSSL and the io_uring shim are not on most hosts, so kyo-net compiles both from source and ships them as classifier jars covering Linux and macOS, and the fast path is opt-in: add all-natives, or your host's pair of classifiers, the transport one (such as linux-x86_64) plus its -boringssl companion, and install nothing else. Windows runs the NIO transport with JDK TLS by design, and no classifier means no native and the floor transport (NIO on the JVM, Node's networking on JS). (by @fwbrasil in #1758, #1831)

  • kyo-schema splits into a format-agnostic core and six format artifacts. kyo-schema now carries derivation, the Codec engine, Structure, and optics. The wire formats ship as six separately published artifacts, each cross-built for JVM, JS, Native, and Wasm: kyo-schema-json, kyo-schema-yaml, kyo-schema-ion, kyo-schema-msgpack, kyo-schema-protobuf, and, new in this release, kyo-schema-bson. A project taking one format no longer drags the other five into its build. This is breaking for every existing user of any wire format, and the migration is in Breaking changes. (by @DamianReeves in #1769, #1742)

  • kyo-i18n (README) parses and formats Fluent (.ftl) bundles in pure Scala, depending only on kyo-core and building on all four platforms. The common Fluent runtime is JavaScript-only. The active locale is a Signal and I18n.t(key, args) returns a bare Signal[String], so a language switch re-renders exactly the affected kyo-ui leaves, with no using parameter threaded through call sites. (by @xsistens in #1775)

  • kyo-markdown (README) renders a Markdown string to a kyo-ui UI tree plus a heading outline through one entry point, Markdown.render, with no third-party Markdown dependency and no bundled syntax highlighter, building on all four platforms. render is pure and total: no call site needs error handling, and the result is a plain value usable anywhere a UI subtree is built, including reactive regions that require pure producers. Raw HTML in the source passes through un-escaped (the trust model a CommonMark renderer applies by default), so a caller rendering untrusted Markdown sanitizes the output itself. (by @fwbrasil in #1764)

  • kyo-stats-machine (README) collects host metrics with no code to call: adding the dependency is the whole integration. The moment kyo.Stat is first touched, a detached fiber samples once a second for the life of the process and writes the full picture of the host into kyo.Stat as a machine.* taxonomy: CPU, memory and swap, per-mount disk, load average, and on Linux cgroup usage and PSI pressure. It works out of the box across OSes and platforms, carrying its own per-OS implementation: the same dependency samples genuinely on the JVM, Native, and JS/Wasm on Node, and a browser JS build degrades gracefully. (by @fwbrasil in #1756)

GraalVM native-image

  • Kyo now has out-of-the-box GraalVM native-image support: a kyo app compiles to a native binary with no hand-authored metadata and no tracing agent. The blocker was the FFM layer, kyo-ffi's JVM Panama backend, kyo-net, kyo-http's native transport, or a user's own binding, where descriptors and reflective accessors had to be hand-authored per binding and went stale the moment a signature changed. That metadata now ships generated, so nothing is hand-maintained. Verified on GraalVM 25. (by @fwbrasil in #1834)

New primitives

  • kyo.UUID is an opaque UUID value type in kyo-data with secure effectful RFC v4 and monotonic v7 generation across platforms, replacing java.util.UUID and UUID-formatted strings. Generation draws from platform cryptographic entropy only and never falls back to Random, timestamp-only UUIDs, process counters, or weak PRNGs. The existing Random.uuid APIs are deliberately untouched, with a migration left to a separate PR. A Schema given renames with it (see Breaking changes). (by @DamianReeves in #1777)

  • OrderedDict[K, V] and OrderedDictBuilder: an immutable, insertion-order-preserving map whose order survives an encode/decode round-trip on every codec. (by @DamianReeves in #1749)

  • SecureRandom: cryptographically secure random as an ambient, let-scoped kyo-core capability with a per-platform secure source, and UUID generation draws from it. (by @DamianReeves in #1777, @fwbrasil in #1833)

kyo-ai

  • kyo-ai now behaves consistently across providers: a streamed turn, a stop at the output ceiling, and a mid-stream provider error are each handled one way on every backend, and each provider's own reasoning vocabulary (a token budget, a named effort level, or no support at all) is declared in the catalog rather than hand-coded per backend. Adding a provider or a model is a catalog entry, not a backend change, and a model's capabilities are declared rather than guessed from its id. (by @fwbrasil in #1765)

  • Claude Code and Codex are now completion backends, so kyo-ai can run on a harness subscription you already pay for instead of per-token API billing. The change sits behind the existing public API: the same Prompt, Tool, Thought, Agent, ai.gen, and ai.stream workflows run unchanged, now through the Claude Code CLI or a local Codex process. Kyo tool execution stays routed through the kyo-ai tool loop rather than exposed as provider shell execution, and a machine's local harness configuration, custom commands, installed plugins, and per-project instructions, never reaches the run: your kyo-ai program determines the behavior, not the install it happens to execute on. (by @fwbrasil in #1728)

  • Reasoning now defaults to on for any provider and model that supports it: a real behavior and cost change, extra output tokens and latency per generation, for any existing config that does not turn it off. The default is configurable, the kyo-ai documentation covers the setting, and the change is also listed in Breaking changes. (by @fwbrasil in #1765)

  • Observe reports what a turn actually cost: a notification-only observer of completed turns carrying per-turn token usage that kyo-ai previously discarded, with Observe.withStats collecting it over a scope alongside the result. On the Claude Code kill-on-capture path, output tokens report as a lower bound. An observer can also enforce a spend cap, failing the generation that breaches it. (by @fwbrasil in #1770)

  • ai.stream previously ignored an instance's config override and enablements while ai.gen honored them. Both now apply the session env consistently, so an instance-level config that was silently inert for streaming takes effect on upgrade. (by @fwbrasil in #1770)

kyo-ui

  • Four families of browser behavior that previously forced an app to reach for the DOM from an effect now have declarative attribute forms, wired in both transports (server-push and the client-only SPA mount). focusAuto / focusRestore move focus in response to the tree changing: focusing a panel as it opens, returning focus when a modal closes. enterTransition / leaveTransition run a CSS transition or animation on an element that a reactive patch would otherwise replace outright, including on removal. inputFilter / inputMask filter or mask text as it is typed, pasted, or dropped, before the character enters the field. preventScrollKeys suppresses the browser's own page scroll for arrow and page keys inside a keyboard-navigation region while still running the element's own key handler. (by @xsistens in #1781, #1787, #1788, #1793)

  • Smaller kyo-ui items: a session-scoped client-command channel with UI.scrollIntoView as its first command, plus Style.whiteSpace, Style.accentColor, server-rendered hover/active styles, and an independent chart axis-title font size (by @fwbrasil in #1766). stopPropagation lets an element consume a bubbling event so a nested overlay's Escape no longer closes the outer panel too, with default behavior unchanged (by @xsistens in #1782). The client-only SPA mount now matches server-push dispatch semantics, so ancestor-declared handlers fire and a submit-button click runs onSubmit exactly once (by @xsistens in #1784, #1785). UI.tbody lands rows patched into a live table in a real row group instead of leaving them as direct <table> children (by @xsistens in #1825).

kyo-test

  • kyo-test's assertGoldenSnapshot snapshots a deterministic generated spread of a type's values, catching wire-format drift a single hand-picked sample misses. (by @DamianReeves in #1771)

Improvements

One Aeron on every platform

  • kyo-aeron now runs on JVM, JS, Native, and Wasm, all four on the same embedded C Aeron client and driver, with the same public API (Topic, AeronClient, TopicException) it had when it was JVM-only. The JVM's separate io.aeron-based implementation was removed entirely rather than kept in sync, and the consolidation retired a use-after-free crash that could occur in rare edge cases. (by @fwbrasil in #1761, #1807)

  • io.aeron and upickle are gone from the module, and no io.aeron type appears on the public surface. Messages now serialize through kyo-schema rather than upickle, a source change for every message type you define (see Breaking changes, which also covers the JVM artifact's new native-library requirement). The four --add-opens the embedded Java driver required are gone, replaced by one advisory --enable-native-access. (by @fwbrasil in #1761, #1807)

Hardening and correctness

  • kyo-http's HTTP/1.1 wire behavior is fixed against the published security-advisory record of seven mature servers: Netty, Tomcat, Jetty, Undertow, Go's net/http, Node's llhttp, and hyper. The changes are to server and client HTTP/1.1 wire behavior in kyo-http, with no API change, and every applicable advisory, including those kyo-http already withstood, stays in the suite as a regression guard. The method: each applicable CVE and GHSA was reproduced as a test putting the advisory's exact bytes on the connection, counted only once it failed for the reason the advisory names and a control (a legitimate message shaped like the attack) still passed. (by @fwbrasil in #1762)

  • In rare edge cases under interruption, Meter could permanently lose a permit. Meter backs mutexes, semaphores, and rate limiters, and at one permit a lost permit is a hard deadlock: every later acquire blocks forever. An interrupt at any point after a successful claim now releases the permit. (by @fwbrasil in #1826)

  • A Flag value containing ; or @ was silently reinterpreted as a rollout expression, with no signal, on every platform. A Windows classpath, a URL with userinfo, or an email address in a flag value resolved to the wrong thing and nothing reported it. Rollout syntax is now explicit opt-in, so a plain value resolves as written, and anyone actually using rollout expressions has a one-line marker to add (see Breaking changes). (by @fwbrasil in #1807)

  • The scheduler's blocking monitor could leave a blocked worker unflagged and uninterrupted after the concurrency regulator shrank the pool, starving the scheduler behind it. (by @fwbrasil in #1761, #1807)

  • Frame derivation could crash on CRLF-encoded sources, the Windows default, and every effectful method requires Frame, so a project with CRLF line endings could fail to compile at all. (by @fwbrasil in #1761, #1807)

  • In rare edge cases during channel and queue shutdown, a flush could hang instead of completing, and a close could leave a channel or queue not actually closed, including at scope exit. Both are fixed. (by @fwbrasil in #1772)

  • ArrowEffect.handleCatching now routes a handler exception to recover on the preempted re-entry path too, restoring the documented contract. (by @fwbrasil in #1757)

  • kyo-net reclaims a backpressured connection whose peer closed, ending a file-descriptor leak. The reclaim is tunable via NetConfig.peerCloseGrace, and a slow but live consumer is never reclaimed. (by @fwbrasil in #1773)

  • kyo-net falls back to the NIO transport instead of crashing on first use when a host has no bundled posix native. (by @fwbrasil in #1829)

  • Random's default nextBytes now fills the full byte range. (by @fwbrasil in #1833)

  • The HTTP client now caps buffered response bodies (HttpClientConfig.maxResponseLength, default 100 MiB, typed failure past it), and kyo-browser streams the Chrome download to disk instead of buffering ~200 MiB in memory. (by @fwbrasil in #1753)

  • System.env and Flag resolution no longer crash browser Scala.js apps with ReferenceError: process is not defined. (by @xsistens in #1823, #1832)

  • Internal hashing moved to a cross-platform xxHash port, and Tag comparison returned to constant time, restoring effect-dispatch performance. (by @hearnadam in #1726, @fwbrasil in #1752)

Schema

  • kyo-schema gains two formats it could not write before, plus schema-document generation, all derived from a type's Schema. BSON is a document-oriented binary format, spec-valid Ion 1.0 binary joins the existing Ion text, and Ion Schema Language 2.0 generation emits a schema document describing a type's wire shape. These three work on JVM, JS, and Native, a narrower reach than the format artifacts' four-platform build. BSON raises rather than silently truncating what it cannot represent (a sub-millisecond Instant, for example). (by @DamianReeves in #1742)

  • The same work surfaced and fixed three silent-corruption defects in formats that already shipped, hitting users who never touch the new formats: Protobuf could silently emit wrong bytes, and Map[String, V] field decode corrupted on every format whenever the schema also carried a field transform. (by @DamianReeves in #1742)

  • Schema.derived now handles sealed case class, and Schema.derivedVia derives through a validating smart constructor, surfacing rejections as typed decode failures. (by @DamianReeves in #1818)

  • Json.encode works on a stock JVM: no more --add-opens java.base/java.lang. (by @DamianReeves in #1803)

  • Yaml.decode no longer panics on a discriminated sealed-trait field inside a List: an unknown variant is a typed failure instead. (by @DamianReeves in #1736)

Tooling and ecosystem

  • kyo-ffi gains a Wasm backend, extending typed C bindings to all four platforms, and kyo-net's and kyo-aeron's Wasm support builds on it. (by @fwbrasil in #1756)

  • Windows is now a tested target: CI exercises windows-x64 across JVM, JS, and Wasm, and the Windows-specific breakages that surfaced are fixed. A kyo-ffi binding capturing errno on Windows silently received GetLastError's value instead of errno. The capture is now correct. On Windows kyo-net runs the NIO transport with JDK TLS, since no native classifier ships for it. (by @fwbrasil in #1761, #1807, #1756)

  • kyo-tasty gains a lazy symbol and occurrence index (go-to-definition, find-references, workspace symbols) decoded on demand from TASTy with no live JVM. (by @fwbrasil in #1727)

  • The Ox kyo-compat binding's acquireReleaseWith (and ensure) now run release when use is cancelled or times out, closing a resource leak. (by @ghostdogpr in #1730)

  • Abort.tap and Abort.tapError observe a failure and re-raise it unchanged, so logging an error on its way out no longer reads as handling it. (by @xsistens in #1776)

  • The codebase is Scala 3.9-ready without moving the Scala version, and the published artifacts' declared JDK requirement is now honest (see Breaking changes). (by @fwbrasil in #1809)

  • A smaller Maven Central footprint ahead of the 2026 per-namespace limits, and kyo-ffi-plugin shrinks from ~33 MB to ~94 KB by resolving its codegen toolchain at task time (see Breaking changes for what stopped publishing). (by @fwbrasil in #1725)

  • The scheduler's top reporter gains a machine-readable status-file sink and now works on Native. (by @fwbrasil in #1729)

Breaking changes

  • Kyo now requires JDK 25. The build's default compilation target moved from -release 17 to -release 25, so nearly every published artifact goes from class-file 61 (Java 17) to 69 (Java 25). This is not confined to kyo-net. In practice RC5's artifacts already could not run on JDK 17: kyo-data and the other foreign-API modules were compiled at -release 25 while kyo-core and its dependents claimed Java 17, so a JDK 17 consumer linked successfully and then failed at runtime. RC6 makes the published metadata match what the code always needed. Still consumable on JDK 17, because they opt back down deliberately: kyo-scheduler and its -zio / -pekko / -finagle integrations, kyo-stats-registry, kyo-config, and the kyo-compat-* bindings. Everything else needs JDK 25. (by @fwbrasil in #1809)

  • kyo-schema no longer ships any wire format: add the matching kyo-schema-json / -yaml / -bson / -ion / -msgpack / -protobuf artifact for each format you use. Projects that relied on kyo-tasty transitively providing the Json codec must add kyo-schema-json explicitly. (by @DamianReeves in #1769)

  • kyo-cats, kyo-scheduler-cats, and kyo-compat's cats-effect (ce) binding are removed, with no in-repo replacement, and no cats-effect binding exists today. The community is invited to maintain these integrations outside Kyo's repository, and kyo-compat now supports exactly that: a backend resolves at external organization:artifact:version coordinates or vendored in your own build. (by @fwbrasil in #1779, #1840)

  • kyo-ai enables reasoning by default wherever the provider and model support it. Any existing config that does not turn it off pays more output tokens and more latency on every generation. The default is configurable, and the kyo-ai documentation covers the setting. (by @fwbrasil in #1765)

  • Flag rollout syntax is no longer implicitly active on any value containing ; or @: it requires an explicit rollout: marker, and a value without the marker now resolves verbatim. Applies to StaticFlag resolution, DynamicFlag init/update/reload, and the FlagAdmin PUT body. Only values actually using rollout syntax need the marker added, and everything else now resolves correctly where it was previously misparsed. (by @fwbrasil in #1807)

  • Schema.dictSchema for a non-String-key Dict moves from a bare two-element array per entry to a two-field key/value record (the form mapSchema already used). MsgPack bytes serialized by an earlier version for such a Dict cannot be read by the new code, so re-serialize. MsgPack was the only codec that decoded the old form (the other six failed and Protobuf emitted corrupt bytes), which bounds where affected data can exist. stringDictSchema is unaffected. (by @DamianReeves in #1749)

  • The Schema given for java.util.UUID is renamed to Schema.javaUuidSchema (Schema.uuidSchema is now the new kyo.UUID). Code that only does summon[Schema[java.util.UUID]] is unaffected, but code naming the old given must use Schema.javaUuidSchema. (by @DamianReeves in #1777)

  • HttpServer.init / initUnscoped / their initWith variants no longer throw a bind failure as a defect: it is Abort.fail(HttpBindException), so the effect row changes and callers recover it like any other typed failure. (by @fwbrasil in #1758)

  • kyo-aeron's published JVM artifact is no longer JARs only: it requires a loadable libkyo_aeron for the host os-arch, and the artifact bundles that native for linux-x86_64 only. On any other host you supply your own and point -Dkyo.ffi.kyo_aeron.path at it. io.aeron is gone from the module. (by @fwbrasil in #1807)

  • Compiler.Pool.init widens from Sync to Async (starting the C driver is an @Ffi.blocking downcall), a compile break only for direct kyo-compiler callers. (by @fwbrasil in #1807)

  • Wasm rows, kyo-bench, kyo-examples, kyo-tasty-fixtures-internal, and the empty kyoJS/kyoNative aggregators are no longer published to Maven Central (Wasm still builds and tests in CI). Anyone depending on those coordinates sees a resolution failure. (by @fwbrasil in #1725)

  • kyo-jsonrpc's JVM-only stream-injection overload of contentLengthStdio is removed. Arbitrary byte-stream pairs go through the public JsonRpcWireTransport seam. A narrow source break for direct callers of that overload. (by @fwbrasil in #1758)

  • kyo-aeron message serialization moves from upickle to kyo-schema's MsgPack codec, so a message type now derives Schema where it previously needed an upickle codec, and every existing kyo-aeron user with their own message type changes its derivation. Interop between RC5 and RC6 nodes is not claimed. (by @fwbrasil in #1761, #1807)

  • XXHash.hash32(String) changes from a content hash over UTF-8 bytes to XXH32 over the four little-endian bytes of the JLS String.hashCode. Internal API, and no released version contains the old derived constants (Protobuf/MsgPack field IDs, Tag.hash), so no user is affected. It is listed because the derivation is documented for external implementers reproducing Protobuf field numbers. (by @fwbrasil in #1752)

New Contributors

  • @xsistens made their first contribution in #1776, and landed 12 PRs in this first cycle, including a whole new module, kyo-i18n.

Full Changelog: v1.0.0-RC5...v1.0.0-RC6