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), withkyo-sql-postgres(README) andkyo-sql-mysql(README), is Kyo's SQL module. Rawsql"..."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 ownnet/tls, a different implementation with different semantics. JVM and Native behavior is unchanged. BoringSSL and theio_uringshim 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: addall-natives, or your host's pair of classifiers, the transport one (such aslinux-x86_64) plus its-boringsslcompanion, 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-schemanow carries derivation, theCodecengine,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 aSignalandI18n.t(key, args)returns a bareSignal[String], so a language switch re-renders exactly the affected kyo-ui leaves, with nousingparameter threaded through call sites. (by @xsistens in #1775) -
kyo-markdown(README) renders a Markdown string to a kyo-uiUItree 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.renderis pure and total: no call site needs error handling, and the result is a plain value usable anywhere aUIsubtree 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 momentkyo.Statis first touched, a detached fiber samples once a second for the life of the process and writes the full picture of the host intokyo.Statas amachine.*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.UUIDis an opaque UUID value type in kyo-data with secure effectful RFC v4 and monotonic v7 generation across platforms, replacingjava.util.UUIDand UUID-formatted strings. Generation draws from platform cryptographic entropy only and never falls back toRandom, timestamp-only UUIDs, process counters, or weak PRNGs. The existingRandom.uuidAPIs are deliberately untouched, with a migration left to a separate PR. ASchemagiven renames with it (see Breaking changes). (by @DamianReeves in #1777) -
OrderedDict[K, V]andOrderedDictBuilder: 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, andai.streamworkflows 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)
-
Observereports what a turn actually cost: a notification-only observer of completed turns carrying per-turn token usage that kyo-ai previously discarded, withObserve.withStatscollecting 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.streampreviously ignored an instance's config override and enablements whileai.genhonored 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/focusRestoremove focus in response to the tree changing: focusing a panel as it opens, returning focus when a modal closes.enterTransition/leaveTransitionrun a CSS transition or animation on an element that a reactive patch would otherwise replace outright, including on removal.inputFilter/inputMaskfilter or mask text as it is typed, pasted, or dropped, before the character enters the field.preventScrollKeyssuppresses 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.scrollIntoViewas its first command, plusStyle.whiteSpace,Style.accentColor, server-rendered hover/active styles, and an independent chart axis-title font size (by @fwbrasil in #1766).stopPropagationlets 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 runsonSubmitexactly once (by @xsistens in #1784, #1785).UI.tbodylands 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
assertGoldenSnapshotsnapshots 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 separateio.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.aeronand upickle are gone from the module, and noio.aerontype 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-opensthe 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,
Metercould permanently lose a permit.Meterbacks 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
Flagvalue 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)
-
Framederivation could crash on CRLF-encoded sources, the Windows default, and every effectful method requiresFrame, 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
flushcould 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.handleCatchingnow routes a handler exception torecoveron 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 defaultnextBytesnow 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.envandFlagresolution no longer crash browser Scala.js apps withReferenceError: process is not defined. (by @xsistens in #1823, #1832) -
Internal hashing moved to a cross-platform xxHash port, and
Tagcomparison 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-millisecondInstant, 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.derivednow handlessealed case class, andSchema.derivedViaderives through a validating smart constructor, surfacing rejections as typed decode failures. (by @DamianReeves in #1818) -
Json.encodeworks on a stock JVM: no more--add-opens java.base/java.lang. (by @DamianReeves in #1803) -
Yaml.decodeno longer panics on a discriminated sealed-trait field inside aList: 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(andensure) now run release whenuseis cancelled or times out, closing a resource leak. (by @ghostdogpr in #1730) -
Abort.tapandAbort.tapErrorobserve 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 17to-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 25while 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-schedulerand its-zio/-pekko/-finagleintegrations,kyo-stats-registry,kyo-config, and thekyo-compat-*bindings. Everything else needs JDK 25. (by @fwbrasil in #1809) -
kyo-schemano longer ships any wire format: add the matchingkyo-schema-json/-yaml/-bson/-ion/-msgpack/-protobufartifact for each format you use. Projects that relied onkyo-tastytransitively providing the Json codec must addkyo-schema-jsonexplicitly. (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 externalorganization:artifact:versioncoordinates 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)
-
Flagrollout syntax is no longer implicitly active on any value containing;or@: it requires an explicitrollout:marker, and a value without the marker now resolves verbatim. Applies toStaticFlagresolution,DynamicFlaginit/update/reload, and theFlagAdminPUT 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.dictSchemafor a non-String-keyDictmoves from a bare two-element array per entry to a two-fieldkey/valuerecord (the formmapSchemaalready used). MsgPack bytes serialized by an earlier version for such aDictcannot 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.stringDictSchemais unaffected. (by @DamianReeves in #1749) -
The
Schemagiven forjava.util.UUIDis renamed toSchema.javaUuidSchema(Schema.uuidSchemais now the newkyo.UUID). Code that only doessummon[Schema[java.util.UUID]]is unaffected, but code naming the old given must useSchema.javaUuidSchema. (by @DamianReeves in #1777) -
HttpServer.init/initUnscoped/ theirinitWithvariants no longer throw a bind failure as a defect: it isAbort.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_aeronfor 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.pathat it. io.aeron is gone from the module. (by @fwbrasil in #1807) -
Compiler.Pool.initwidens fromSynctoAsync(starting the C driver is an@Ffi.blockingdowncall), 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 emptykyoJS/kyoNativeaggregators 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
contentLengthStdiois removed. Arbitrary byte-stream pairs go through the publicJsonRpcWireTransportseam. 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 Schemawhere 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 JLSString.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