Build something that holds.

AI can write the code. Making it hold up under real use is the part that has not changed. Kyo is the foundation that takes that on, with layered safety from the first line of code to crash recovery, so what you build survives errors, restarts, and real traffic.

Open source· Apache-2.0· Scala 3· Server, browser, native, and Wasm
SCALA
val checkout: Receipt < (Async & Abort[Declined]) =
for
auth <- bank.authorize(card, total)
done <- orders.record(auth)
yield done
// every effect and failure, in the type
The gap

From "it works" to "you can depend on it."

The demo works. Then an error slips through unnoticed, a restart wipes the night's work, or a little real traffic shows up and the whole thing buckles. The distance between software that works once and software you can depend on is the gap most projects fall into, and the more of the code an AI wrote, the more the ground underneath has to hold.

4 in 5chance of failure, 1 to 10 chained steps
Small errors compound.
Each step works 85% of the time, a model call, a tool, a flaky external API. Chain ten of them and the chance the whole run fails somewhere climbs to about four in five. That is why software that demos perfectly comes apart in real use.
Platforms and the engine

One codebase. Four platforms. One process that carries the load.

Almost every module compiles to all four targets from one source, so the choice below is where your program runs, not which features you get. The same APIs come with it; only the runtime underneath changes.

one codebase
Multi-threaded
JVM

The mature platform most production already runs on, where the work-stealing scheduler spreads fibers across every core. It has the widest library reach of the four.

Browser and Node
JavaScript

One source runs in the browser and on Node, so a web UI, an edge function, and a backend can share the same code and the same APIs.

Instant startup
Native

Compiles to a standalone binary that starts in milliseconds with no runtime to install, for command-line tools and long-running services alike.

Near-native
WebAssembly

The Scala.js WasmGC backend runs the same code at near-native speed, in the browser or any Wasm host.

And the engine under all of it: compiled code, an effect runtime built around allocation discipline, and an adaptive work-stealing scheduler that keeps every core fed. One process holds thousands of concurrent computations, where the default stack of the AI ecosystem scales by adding worker fleets. Latency and throughput per process are the serving bill, and the serving bill is what decides whether you can afford to run what you built.

Layered safety

As you write. As it compiles. As it runs. When it fails.

One foundation carries your code from the first line you write to a crash and back, and it catches mistakes earlier at every step: as you write, as it compiles, as it runs, and when it fails anyway. You opt into none of it. There are no conventions to follow, no annotations to add, and no cleanup to wire, because the safe path is the default the API hands you, whether a developer wrote the code or an AI agent generated it.

1
As you write

Whole categories of bug never reach the keyboard.

The shapes that break a program cannot be expressed in the first place, so you spend your time on logic instead of guarding against invalid states. The UI layer turns the wrong markup back right where you write it: an SVG primitive is not an HTML child, and the compiler says so before it reaches the screen.

div(span("ok"))         // compiles
div(Svg.circle(...)) // does not: an SVG primitive is not an HTML child

The same check reaches the request: an auth filter does not compile until the route declares the header it reads, then hands the verified user to the next handler as a typed field.

2
As it compiles

The compiler catches what slipped past you.

Every effect a piece of code uses, and every way it can fail, is part of its type:

def charge(card: Card, amount: Money): Receipt < (Async & Abort[Declined])

This function can suspend, and it can be declined. Nothing else. Forget to handle that failure and it does not compile, because the unhandled effect stays in the type until you deal with it. Every rejection points at the exact line, so whoever wrote it, a person or a model, corrects it in a step instead of a rewrite.

3
As it runs

The runtime steadies itself, so your code stays simple.

Work started together is torn down together, and anything acquired in a scope, a connection, a file, a handle, is released exactly once: on success, on failure, and on interruption alike.

The scheduler keeps every task moving on a 10ms slice and catches a blocking call by watching it stop using the CPU, the socket reads and native I/O that still look like running threads to every other runtime. It sizes its own pool to the machine and sheds load by a stable per-user decision before the queue can OOM, and flaky calls retry on a policy and time out cleanly instead of hanging.

4
When it fails anyway

A crash costs a restart, not the work.

Long-running work records each step before the next begins, so the process can go down anywhere and resume from the last completed step, replaying nothing it already finished.

It does not even need the same machine: each run is held on a time-limited lease, so a stalled executor's work is claimed by another and carried forward. Even a one-hour sleep survives a restart, and a half-finished transaction unwinds itself in reverse. No separate workflow server to stand up; the durability is part of the same foundation as the rest.

Agents get all four layers, in both directions.

The code an AI writes is held by the same APIs and contracts as yours, and the agent it builds runs inside the same runtime and durability: a failed tool call is a typed error, a multi-step run is a durable workflow, a runaway loop is preempted on its time slice. Nothing about AI is a special case.

The same type system that checks your code checks your agents.

Kyo doesn't make bugs impossible. What it does is take the failure modes that wreck most projects off the table, and catch many of the rest before they ship.

Start where you are

Keep what you already have.

Adopting Kyo is not a rewrite. Bring it in next to the code you run today, one call at a time, and the two compose in a single program. Failures and cancellation cross the boundary in both directions, so nothing leaks when you mix them.

Already on ZIO or Cats Effect?

Call into Kyo from your effect type and run Kyo as either, both ways. Failure and interruption semantics are preserved across the boundary, so a cancel on one side cancels the other.

Want only the runtime?

Install the work-stealing scheduler as the execution context your service already runs on, a drop-in for Cats Effect, ZIO, Pekko, or Finagle. Future-based code gets the same time-slicing and blocking detection underneath, on a pool that sizes itself to the machine.

Want no runtime?

Not every module needs the scheduler. kyo-prelude handles typed errors, environment, and state in place with no runtime, and kyo-data, kyo-schema, and kyo-parse are plain libraries.

Starting fresh?

The whole foundation is one import away. import kyo.* brings the entire vocabulary, and adding a module adds its types to that same import.

SCALA
// Kyo composes with ZIO and Cats Effect, both ways

val fromZio: User < (Abort[E] & Async) = ZIOs.get(loadUser)
val toZio: ZIO[Any, E, Receipt] = ZIOs.run(checkout)
val fromCats: User < Async = Cats.get(cachedUser)
val toCats: IO[Receipt] = Cats.run(checkout)

This project exists because of a specific belief about what software is for and who gets to build it. Read the manifesto.

Build something that holds.