Overview

Conduit is a Scala 3 / ZIO 2 library for unidirectional state. Actions describe what happened. Handlers turn those into a new immutable model. Listeners react to slices that actually changed.

It cross-builds for JVM, Scala.js, and Scala Native. The docs site is JVM + a Scala.js client that remounts the live widgets; the library itself has no UI dependency.

libraryDependencies += "rocks.earlyeffect" %% "conduit" % "<version>"

Use %%% in a Scala.js or Native build. Pair with ascent-conduit when the host is an ascent UI; that bridge is optional and lives in ascent, not here.

The loop

Enqueue is cheap and asynchronous. Nothing is applied until run(). Follow-ups returned from a handler are dispatched immediately (nested), then the loop continues. Click a node in the diagram to highlight it.

Mermoid.diagram(loop)
changedsame
Mermoid.diagramInteractive(loop, initialWidth = 720)
viewport 720px
changedsame

Four pieces

PieceJob
ModelImmutable case class, usually derives Optics
Actionenum X extends Action (alias for AppAction[Any, Nothing])
HandlerPartial function from action to ActionResult on a lensed slice
ConduitQueue + Ref + dispatch loop + listeners

Read Getting started for a clickable counter, then Mental model for how FastEq, follow-ups, and run vs run(false) fit together.