Kyo

repository·main·Indexed 21 days ago

https://github.com/getkyo/kyo

A Scala 3 toolkit for building applications using algebraic effects. Kyo provides strong safety guarantees to ensure that unhandled error paths, undeclared effects, and resource leaks are caught at compile time. It includes kyo-actor for implementing actor-based concurrency with support for various receive combinators (receiveAll, receiveMax, receiveLoop), request-response patterns via ask, and lifecycle management through Scope inheritance.

Tokens
310.2K
Snippets
848
Records
1K
Agent score
73%

What's inside kyo

  1. Overview of kyo-compat

    main

    What is kyo-compat?

    kyo-compat is a compatibility layer that allows you to write a library once against the kyo.compat.* surface and deploy it across five different backends. This enables cross-backend portability without sacrificing performance or backend-specific features.

    Key Benefits

    • Overhead-free: Every method is an inline def that lowers to the backend's primitive at the call site. There is no typeclass dispatch or adapter layer overhead.
    • Runtime-free: Each backend artifact (e.g., kyo-compat-zio) depends only on its target runtime, not on other Kyo modules.
    • Uniform surface: Provides a consistent API for fibers, promises, channels, atomics, latches, meters, fiber-locals, time, and concurrency.
    • Preserves backend features: Features like ZIO Trace, Kyo Frame, fiber locals, scoped resources, and runtime stack traces flow through CIO unchanged.

    Supported Backends

    The cross-backend computation type CIO[+A] is an opaque alias that resolves differently depending on which backend artifact you include in your project:

    BackendCIO[+A] resolves toProvided by
    KyoA < (Abort[Throwable] & Async)kyo-compat-kyo
    ZIOzio.ZIO[Any, Throwable, A]kyo-compat-zio
    FutureLocalCtx => scala.concurrent.Future[A]kyo-compat-future
    Ox(Int, ox.Ox) => Akyo-compat-ox
    Twitter Future() => com.twitter.util.Future[A]kyo-compat-twitter-future
  2. Overview of kyo-data

    main

    kyo-data is the foundational data layer for the Kyo ecosystem. It provides high-performance, immutable, and opaque-type-backed alternatives to standard library types like Option, Either, Try, Map, IArray, and java.time.

    Key characteristics:

    • Low Allocation: Many types (like Maybe and Result) are unboxed at runtime, meaning they carry no wrapper allocation for the happy path.
    • Rich Type Encoding: Uses advanced type-level features like Record[F] for schema encoding and Tag[A] for runtime type identity.
    • Cross-Platform: Provides an identical public surface across JVM, Scala.js, Scala Native, and Wasm.
    • Design Patterns: Uses opaque types over existing values, type-level structure encoding, and Kyo ecosystem conventions (e.g., Frame for call-site position, Render[A] for printing).
  3. Overview of kyo-caliban

    main

    kyo-caliban allows you to serve a Caliban GraphQL API using a kyo-http HttpServer. It bridges Kyo effect rows directly into Caliban resolver machinery.

    Key features:

    • Resolver field types can be Kyo computations (e.g., Int < Async, String < Abort[Throwable]).
    • Supports standard Caliban schema derivation.
    • Provides a single call to serve an interpreter as an HTTP server.
    • Handles POST/GET queries, SSE subscriptions, @defer multipart streaming, multipart uploads, GraphiQL, and WebSockets (graphql-transport-ws and graphql-ws).
    • Note: This project is JVM-only because it depends on caliban-core.
  4. Overview of kyo-compiler

    main

    The kyo-compiler provides a warm, per-config handle to the Scala 3 presentation compiler (scala.meta.pc). It is designed for IDE-intelligence operations over Scala source text.

    Key Features:

    • Six Intelligence Ops: compile (diagnostics), completions, hover, signatureHelp, symbol (go-to-symbol), and didClose (cache eviction).
    • Offset-based Results: All operations return results using UTF-16 code unit offsets, making it easy to integrate with editors without managing complex URI or LSP objects.
    • Concurrency & Cancellation: Every operation is cancellable by interrupting the calling fiber. Operations on a single handle are serialized.
    • Lifecycle Management: Uses a Compiler.Pool to manage compiler instances, handling lazy initialization, concurrency limits, and LRU eviction.

    Important Constraints:

    • JVM Only: This module has no JS or Native targets.
    • Stateless Handles: The Compiler handle is a view, not a live instance. It does not hold its own buffer; you must pass the uri, text, and offset with every call.
    • Identity via Config: A Compiler handle is bound to a specific Compiler.Config. Any change to the configuration results in a distinct instance.
  5. Overview of kyo-mcp

    main

    kyo-mcp is a Model Context Protocol (MCP) implementation that provides both a server for exposing capabilities to LLM hosts (like Claude Desktop or IDE agents) and a client for driving other MCP servers.

    Key characteristics:

    • Multi-runtime: Runs on JVM, JavaScript, and Scala Native.
    • Transport-agnostic: Built on kyo-jsonrpc and works over any JsonRpcTransport (stdio, Unix domain socket, in-memory pipe, or custom wire).
    • Typed Interface: Servers are defined as a list of McpHandler values. The engine automatically handles JSON-RPC decoding/encoding, schema derivation, and the MCP handshake. Clients use McpClient.init to expose typed methods for each MCP request.
  6. Overview of Kyo Modules

    main

    Kyo is organized into several specialized modules categorized by their purpose. Each module is designed to be used either as part of a larger Kyo program or as a standalone component.

    Core Modules

    These are the foundational building blocks for any Kyo application:

    • kyo-core: Provides I/O and concurrency primitives like Sync, Async, Scope, Fiber, Channel, Hub, Queue, Clock, Log, and Path.
    • kyo-prelude: A strictly-pure effect layer containing Abort, Env, Var, Memo, Choice, Emit, Poll, Stream, and Layer.
    • kyo-data: Low-allocation data types including Maybe, Result, Chunk, Span, Duration, Instant, Schedule, and TypeMap.
    • kyo-kernel: The algebraic-effects substrate defining A < S, ArrowEffect, ContextEffect, and multi-shot continuations.
    • kyo-scheduler: An adaptive work-stealing pool with automatic blocking detection and admission control.

    Application & Specialized Modules

    Kyo provides high-level modules for building complete applications:

    • Applications: kyo-http (HTTP client/server), kyo-schema (validation/lenses), kyo-config (type-safe config), kyo-flow (durable workflows), kyo-ui (web UIs), kyo-ai (LLM programs), and kyo-caliban (GraphQL).
    • Concurrency: kyo-actor (typed actors), kyo-stm (Software Transactional Memory), and kyo-offheap (typed primitive arrays).
    • Specialized Tools: kyo-parse (parser combinators), kyo-pod (Docker/Podman), kyo-browser (browser automation), kyo-mcp (Model Context Protocol), kyo-lsp (Language Server Protocol), and kyo-ffi (C library bindings).
    • Observability: kyo-stats-registry (metrics), kyo-stats-otlp (OTLP exporter), and logging bridges (kyo-logging-jpl, kyo-logging-slf4j).
    • Interop: kyo-compat (write once for multiple runtimes), kyo-reactive-streams (Reactive Streams bridge), and kyo-zio (ZIO bridge).
  7. Overview of kyo-jsonrpc architecture

    main

    kyo-jsonrpc implements bidirectional JSON-RPC 2.0 messaging between two peers over a pluggable transport. A 'peer' is a JsonRpcHandler that can act as a server (answering requests), a client (calling out), or both.

    The architecture consists of three layers:

    1. JsonRpcHandler: The top layer that manages the dispatch loop and provides typed operations like call, notify, callWithProgress, and cancel.
    2. JsonRpcTransport: The middle layer that ferries JsonRpcEnvelope messages in either direction.
    3. JsonRpcWireTransport + JsonRpcFramer: The bottom layer that converts raw byte streams into envelopes using a Schema[JsonRpcEnvelope].

    Handlers use a typed JsonRpcError hierarchy for protocol errors and allow user-domain errors to be registered via .error[E2] to flow back to peers as wire error responses.

  8. Overview of kyo-lsp

    main

    kyo-lsp is a Language Server Protocol (LSP) 3.17 implementation built on top of kyo-jsonrpc. It allows developers to build both editor-tooling servers and clients using typed handlers.

    Key Concepts

    • Server: Composed of a JsonRpcTransport and a list of typed LspHandler[In, Out, +E] values. The engine manages the initialize handshake, capability advertisement, document registry, and request dispatching.
    • Client: Requires an identity record (LspInfo), a capability tree (LspCapabilities), and a transport. The client performs an eager handshake during initialization.
    • Handlers: Typed functions that process inbound messages. Handlers can access per-request state (the server instance, document registry, or cancellation promises) via Lsp.* accessors.
    • Error Handling: Uses a sealed LspException hierarchy. User-domain errors can be registered per-handler using .error[E2](code, message) and are transmitted to the peer as LspRemoteException.
  9. Introduction to kyo-parse

    main

    A parser in kyo-parse is a Kyo computation of type A < Parse[In]. It consumes elements of type In from a position-tracked input and either produces a value of type A (advancing the position) or drops the current parse branch so an enclosing alternative can try something else.

    Key Behaviors

    • Backtracking: firstOf tries alternatives in order, rewinding the input on each failed attempt. attempt exposes this backtracking as a Maybe[A] so you can branch on it explicitly.
    • The Cut: require commits to a parser. If a failure occurs inside a require block, it is treated as a fatal failure that firstOf will not swallow. This is used for error recovery and partial-AST reporting.

    In is parametric; while often Char, you can parse any token stream (e.g., Parse[Int], Parse[Token]).

    val greeting: String < Abort[ParseError] =
        Parse.runOrAbort("hello")(Parse.literal("hello"))
    
    val n: Int < Abort[ParseError] =
        Parse.runOrAbort("42")(Parse.entireInput(Parse.int))
  10. Use Amazon Ion codecs with kyo-schema-ion

    main

    The kyo-schema-ion library provides several entry points for working with Amazon Ion data for any type that has a Schema instance:

    • Ion.encode: Encodes a value to Ion text or binary.
    • Ion.decode: Decodes Ion text or binary into a value.
    • IonBinary: A standalone codec specifically for Ion binary format.
    • IonSchema: Used for generating Ion Schemas.
  11. Supported Platforms and Runtimes

    main

    Kyo supports four primary publication targets with different runtime characteristics:

    • JVM: Requires JDK 21+. Uses a multi-threaded work-stealing scheduler.
    • Scala.js: Runs in Node.js or browsers. Uses a single-threaded, event-loop concurrency model.
    • Scala Native: Produces native binaries via LLVM. Uses a multi-threaded work-stealing scheduler.
    • WebAssembly: Uses the experimental Scala.js WebAssembly backend (WasmGC). Requires Node.js 24+ and uses V8's Turboshaft Wasm pipeline. Kyo passes --experimental-wasm-exnref for exception handling.

    Note: Scala.js and WebAssembly share the same single-threaded, event-loop concurrency model.

    | Platform     | Runtime              | Coordinate |
    | ------------ | -------------------- | ---------- |
    | JVM          | JDK 21+              | `%%`       |
    | Scala.js     | Node.js, browsers    | `%%%`      |
    | Scala Native | Native binary (LLVM) | `%%`       |
    | WebAssembly  | Node.js 24+          | `%%%`      |
  12. Understand the kyo-stats-registry telemetry substrate

    main

    kyo-stats-registry is the low-level metrics and tracing layer used by Kyo to report telemetry. It uses a hierarchical, path-based namespacing system where modules request a Scope (a dotted path like "kyo" :: "fiber" :: Nil) and then mint instruments (counters, histograms, gauges, etc.) from that scope.

    Key Characteristics:

    • Deduplication: Instruments are singletons per path. Multiple calls for the same instrument name under the same scope return the same handle, ensuring process-wide consistency.
    • Memory Management: Instrument handles are held via WeakReference. If all callers drop their handles, the instrument is evicted from the registry and its state is lost. You should hold a strong reference (e.g., a val in your module) to keep metrics alive.
    • Unsafe Layer: Most methods in kyo.stats.internal are marked Unsafe. They skip the effect system for performance in hot paths or exporters. Application code should generally use the higher-level Stat API in kyo-core instead.