okay-effects

Effects in other languages

The same idea, a program that asks operations and handlers that answer them, is implemented outside Scala in nine languages: Java, Kotlin, Rust, Go, Goose, Zig, TypeScript, Python and Lean. Each takes the form its language allows: a program as data run by a machine, direct style on the language's own continuations, coroutines or generators, a function compiled into a state machine, or a plain function over a typed context. Three things hold them to one meaning: one digest of a thousand random programs, test suites carried from one repository to another, and the okay wire, on which a program in one language is answered by handlers in another.

As of 11 November 2026: the state of the default branches. Every statement on this page was checked in the repositories; where a file says it, the file is named. The Scala implementations have a page of their own.

The implementations

Eleven repositories, all public. Three are released: okay-direct, okay-kotlin and okay-zig. Java and Rust appear more than once: each has a library and a kernel of the reference model.

RepositoryLanguageHow a program runsThe effects of a program are checkedContinuationsStatus
okay-java Java 25 As data. Eff<L, A> is nodes run by a machine over an explicit stack of delimiters; an operation is a shift0 to its handler's prompt. A second notation, okay.rows, on the same machine: Comp<A, R>, the interface of okay-effects' Java kernel. A Bridge runs a program of either notation inside the other. By javac. An effect is an interface at a level L; a handler's body is a generic method at a level of its own; Eff.run takes a program at Top. In okay.rows the row is a nested type, by position, as in okay-effects' Java kernel; run takes the empty row. Multi-shot: k is the captured part of the machine's stack. Public. No release. Last commit 11 Nov 2026.
okay-direct Java 25 In direct style: perform is a method call. Three implementations: HotSpot's internal continuations (Loom), virtual threads, Espresso's continuations. By javac. A program takes a capability, Effect<F>, for each effect. A capability found by key (Implicit) is checked at run time. One-shot on Loom and on threads. Multi-shot on Espresso: a resumption runs a copy of the frames. Released, 0.1.0. Last commit 23 Oct 2026.
okay-effects, java/ Java 25 As data: Comp<A, R>, one loop over a stack of levels, one level a handler. By javac. The row is a nested type, by position: Comp<A, Eff<State<Integer>, Eff<Choose, ?>>>; run takes the empty row. Multi-shot: k is immutable levels, shared. Public. Used from source. Last commit 11 Nov 2026.
okay-kotlin Kotlin 2.4. JVM, JS, native Two styles. Interfaces: an effect is an interface of suspend functions, on Kotlin's coroutines. Data: Prog<F, R, A>, run by a CEK machine written after okay-scala's, or by the coroutines. By the compiler. Interfaces: context parameters. Data: rows and typed places. Interfaces: k is resumed once; k.copy() copies the frames, on the JVM and JS, not on native. Data on the machine: multi-shot on every platform. Released, 0.1.0. Last commit 23 Oct 2026.
okay-rust Rust, edition 2024 Three crates. okay: an async function over a context, the compiler's state machine. okay-resumable: a macro makes a function an enum of its stops. okay-machine: a program as data, Eff<R, A>. By rustc. okay: trait bounds on the context, Has<E, Ix>, written by needs!. okay-machine: a row is a list of types. okay: one-shot, a future cannot be cloned. okay-resumable: multi-shot, the enum is Clone. okay-machine: multi-shot, k is data. Public. Not on crates.io. Last commit 28 Oct 2026.
okay-effects, rust/ Rust, edition 2024 As data, composed statically: impl Prog<A, eff![State<i64>, Choose]> is a struct of structs, run by one loop. By rustc. The row is a list of types; run asks for the empty one. Multi-shot: K is Clone. A computation is run once, on one thread. Public. Used from source. Last commit 11 Nov 2026.
okay-go Go 1.27 In direct style on Go's coroutines (iter.Pull). Package prog: programs as data. Not as a set. A program's effects are its capabilities, Cap[O], passed as parameters; an operation's answer is typed. A capability used outside its handler is refused at run time. One-shot: a coroutine cannot be copied. Multi-shot in prog. Public. "An experiment" (its README). Last commit 18 Oct 2026.
okay-goose Goose, which compiles to C By a translator, okgc, written in Goose: an effect becomes operations over a context, monomorphized; a resumable fn becomes a state machine. By okgc, at the definition: a function of type A ! F + G calls only the operations of its effects. Then by Goose: a context without an operation is its error. By the effect's kind: tail, once, many. The rest is a struct, copied; it can be written out as bytes. Public. No release. Last commit 28 Oct 2026.
okay-zig Zig 0.17 Two layers with one set of handlers. Contexts: a plain function, an operation an inlined call. The machine: a program as data. And resumable: a union of a program's stops, written by hand. At compile time. ok.needs for a context; a row is a tuple of types, and an effect not in it is a compile error. A guarded effect answers an error union. The machine: multi-shot. A resumable union is copied by value. Released, 0.1.0. Last commit 28 Oct 2026.
okay-ts TypeScript 7, Node 26 As data on a machine: a node and a persistent stack of frames. A program is written as a generator or as data. By tsc. The row is a union in the program's type; run() exists only for the empty row. A cast passes it. A generator: once, and its type says so. Data: multi-shot. A handler that resumes many times takes data only. Public. Not on npm. Last commit 15 Oct 2026.
okay-python Python 3.11+ On one machine with a persistent stack of frames. A program is written as a generator, yield from cap.perform(op), or as data. Not as a set. Effects are capabilities passed as parameters. mypy --strict types an operation's answer; which operations a capability takes is checked at run time. A generator: once. Data: multi-shot. A handler that resumes many times (resuming, all_paths) takes data only; mypy --strict refuses a generator there. Public. Not on PyPI. Last commit 11 Nov 2026.
okay-lean Lean 4.35 As data: okay-simple's Free monad, ported. By Lean. The row is a list of effects in the type; run exists only for A ! []. Multi-shot: k is a pure function. Public. No release. Last commit 11 Nov 2026.

okay-direct also has front ends for Scala 3 and 2.13; they are on the Scala page. okay-rs is the earlier repository of okay-rust; its README says it has moved, and its history is in okay-rust. okay-effects is the reference model: one small kernel written three times, in Scala 3, Java 25 and Rust.

One rule holds across the family: a continuation resumed many times is a real value, a copy of frames, a cloned state machine or data; a body is never run again from its start. Where a language's own continuation cannot be copied (a generator in Python and in TypeScript), it is resumed once, and a program that must be resumed many times is written as data.

A program in each

Copied from each repository's own documentation or tests; the file is named.

okay-java (README.md)

interface Ask<L> { Eff<L, Integer> number(); }
interface Asked<L, A> { <M extends L> Eff<M, A> in(Ask<M> a); }   // a handler's body: a level of its own

static <L, A> Eff<L, A> asking(int n, Asked<L, A> body) {
  return Eff.handle(new Eff.Body<L, A, A>() {
    public <M extends L> Eff<M, A> in(Prompt<L, M, A> p) { return body.in(() -> p.shift0(k -> k.apply(n))); }
  }, Eff::pure);
}

okay-direct (README.md)

public sealed interface State<S> {
    record Get<S>() implements State<S>, Op<State<S>, S> {}
    record Put<S>(S value) implements State<S>, Op<State<S>, Void> {}
}

public void operation(State<S> op, Answer<State<S>> k) {
    switch (op) {
        case Get<S> get -> k.answer(get, state);
        case Put<S> put -> { state = put.value(); k.answer(put, null); }
    }
}

A program is plain Java that takes the capability: static int total(Effect<Prices> prices, Effect<Fail<String>> fail, List<String> cart), and performs inside a stream's lambda.

okay-effects, the Java kernel (README.md)

static Comp<Integer, Eff<State<Integer>, ?>> add(int x) {
  return State.<Integer>get().flatMap(s -> State.put(s + x).map(done -> s + x));
}
static Comp<Integer, Eff<State<Integer>, Eff<Choose, ?>>> p() {   // a state, and a choice under it
  return up(Choose.among(List.of(1, 2))).flatMap(x -> add(x));
}

run(Choose.all(State.run(0, p())));   // [Final[state=1, value=1], Final[state=2, value=2]]

okay-kotlin, interfaces (core/src/commonTest/…/CoreTest.kt)

fun interface Ask {
    suspend fun ask(): Int
}

context(a: Ask) suspend fun askFor(): Int = a.ask()

/** each ask answered with `n`, the rest resumed in the clause: a general handler in tail position */
suspend fun <A> answering(n: Int, body: suspend context(Ask) () -> A): A = handle { prompt ->
    context(Ask { prompt.shift { k -> k(n) } }) { body() }
}

okay-rust, the crate okay (README.md)

okay::needs! {
    async fn counted(cx: [Reader<i64>, State<i64>, Writer<String>], n: i64) -> i64 {
        eff! {
            d <- ask(cx);
            _ <- modify(cx, |s| s + d * n);
            s <- get(cx);
            _ <- tell(cx, format!("s {s}"));
            yield s
        }.await
    }
}
let cx = Cx(AskWith(2i64), Cx(StateCell::new(1i64), Cx(Collect::<String>::new(), End)));
assert_eq!(run(counted(&cx, 10)), Ok(21));

okay-rust, a resumable function (README.md)

okay::effect! { pub enum Choose: Plain { Among(n: usize) -> usize = among; } }
okay::ops! { pub enum ChooseOps { Choose } }    // the operations it may stop at: an enum, `From` each effect

#[resumable(ChooseOps)]
fn pick(base: usize) -> usize {
    let a: usize = ask!(Choose::Among(3));      // a stop: the operation given to the handler
    let b: usize = ask!(Choose::Among(2));
    base + a * 10 + b
}

okay-effects, the Rust kernel (README.md)

fn p() -> impl Prog<i64, eff![State<i64>, Choose]> {
    Choose::among(vec![1, 2])
        .flat_map(|x| State::get().flat_map(move |s: i64| State::put(s + x).map(move |_| s + x)))
}

Choose::all(State::run(0, p())).run();   // [(1, 1), (2, 2)]
State::run(0, Choose::all(p())).run();   // (3, [1, 3])

okay-go (example_test.go)

// An operation: a struct embedding Answers[R], R being what it answers.
type Ask struct{ okay.Answers[int] }

got := okay.Main(func(r *okay.Run) int {
	return okay.Answer(r, func(Ask) int { return 1 }, func(outer okay.Cap[Ask]) int {
		return okay.Answer(r, func(Ask) int { return 2 }, func(inner okay.Cap[Ask]) int {
			return okay.Perform(outer, Ask{})*10 + okay.Perform(inner, Ask{})
		})
	})
})   // 12

okay-goose (examples/handlers.okg)

effect Choose: many { among(n: i64) -> i64; }
effect Log { log(line: u8[:]); }

resumable fn pair() -> i64 ! Choose + Log {
    let a = among(3);
    log("a chosen");
    let b = among(2);
    return a * 10 + b;
}

handler all for Choose(out: i64[>..]&) {
    return(v) { out.push(v); }
    among(n, k) { for i in n { resume(k, i); } }
}

okay-zig, a context (README.md)

/// a plain function: its effects the context's, each operation a call — an effect missing, a compile error
fn greet(cx: anytype) usize {
    ok.needs(@TypeOf(cx), .{ Name, Counter });
    const who = cx.op(Name, .ask, {});
    const n = cx.op(Counter, .get, {});
    cx.op(Counter, .put, n + 1);
    return who.len * 100 + n;
}

var cell: u32 = 7;
const cx = ok.context(.{ Counter.Cell{ .s = &cell }, Name.Given{ .env = "Ann" } });
_ = greet(cx);                                              // 307

okay-ts (README.md)

const Config = Reader("Config", of<number>())
const Counter = State("Counter", of<number>())

const program = eff(function* () {
  const n = yield* Config.ask()
  yield* Counter.modify((s) => s + n)
  const s = yield* Counter.get()
  return s * 2
})
// program: Eff<number, Reader<"Config", number> | State<"Counter", number>, boolean>

program.handle(Config.value(5)).handle(Counter.from(1)).run() // [6, 12]

okay-python (tests/test_core.py)

@dataclass(frozen=True)
class Ask(Op[T], Generic[T]):
    pass

def reader(v: T, body: Callable[[Cap[Ask[T]]], Eff[A]]) -> Eff[A]:
    return (yield from answering(Ask, lambda _: v, body))

def prog(n: Cap[Ask[int]]) -> Eff[str]:
    def body(s: Cap[Ask[str]]) -> Eff[str]:
        return (yield from s.perform(Ask[str]())) * (yield from n.perform(Ask[int]()))

    return (yield from reader("ab", body))

self.assertEqual(run(reader(3, prog)), "ababab")

okay-lean (README.md)

-- in any row that has these three, at any place
def greet [In (Reader String) R] [In (Writer String) R] [In (State Nat) R] : Nat ! R := do
  let name : String ← ask
  tell s!"hello, {name}"
  let n : Nat ← get
  put (n + name.length)
  pure n

#eval run (writer String (state 10 (reader "Ann" (greet (R := [Reader String, State Nat, Writer String])))))
-- ((10, 13), ["hello, Ann"])

What a language allows

Each form follows from what the language has: a continuation that can be copied or not, types that can hold a set of effects or not, a compiler that can be extended or not.

Java

Java has no higher kinds and no type-level lists. Three answers are in the family. okay-direct keeps no row at all: a program is plain code, an effect is a sealed interface whose operations are records, a handler is an exhaustive switch, and the operation is the witness of its answer's type. What can be resumed depends on the JVM: HotSpot's continuation and a virtual thread are resumed once; Espresso can copy a suspended continuation's frames, so only EspressoEffects is a MultiEffects, and Choose.all does not compile against the other two. okay-java puts the handlers in force into a type variable: a handler's body is a generic method at a level M extends L that nothing outside can name, so a capability that leaves its handler does not compile (LeakTest). The price is in its README: a lambda cannot implement a generic method, so every handler's body is an anonymous class or a method reference. Its second notation, okay.rows, is the interface of okay-effects' Java kernel, below, on okay-java's own machine (docs/rows.md). The Java kernel of okay-effects writes the row as a nested type with wildcards. It is positional: a program names its effects in the order of its handlers and is moved with up, under and fit; a handler takes its effect from the front of the row only.

Kotlin

Context parameters carry the effects: context(accounts: Accounts, fail: Fail<String>) on a suspend function is checked by the compiler. A handler that takes the rest of the body is a delimited continuation on the standard library's coroutines. A Kotlin continuation is resumed once; k.copy() copies the objects the compiler made of the suspend functions, up to the handler. That works on the JVM and in JavaScript; native code has no way to copy a frame, and the multi-shot tests are in a source set for the JVM and JS only. Handlers are chosen lexically: an operation goes to the handler whose capability it was given. The data style is the other answer: k is data on a machine, on every platform.

Rust

An async block is a state machine the compiler builds, generic over its context and monomorphized for the handlers it runs under; an operation answered in place is an inlined call. A future cannot be cloned, so the crate okay is one-shot by design. Where the rest must be taken many times, the rest has to be a value that is Clone: #[resumable] turns a function into an enum, one variant for each stop holding the variables in scope there, on stable Rust; with the feature coroutines, on nightly, the same comes from a coroutine that is cloned. Ownership does part of the typing: a state whose type changes from step to step is a token each step takes and gives back, and a context is a borrow that cannot outlive its handlers. In the Rust kernel of okay-effects a closure given to flat_map is FnOnce + Clone, a recursive program ends with .boxed(), and everything is of one thread.

Go

Go has no type-level lists, so a program's effects cannot be in its type; they are its capabilities, parameters and fields, as a Go program passes ctx. A handler answers only its own capability's operations, so two instances of one effect coexist. A program is a coroutine (iter.Pull); it cannot be copied, so a continuation is resumed once. Parallel branches run on goroutines, and a branch performs through a capability only after it is lent to it; its operations travel over a channel to the goroutine that owns the handler. Multi-shot is a separate package of programs as data.

Goose

Goose has no heap, no garbage collector, and function values only at compile time. So a set of effects is a context's type, a handler is an overload of the operations for that type, and an interceptor is a generic wrapper of a context. okay-goose is a translator, okgc, written in Goose: it reads Goose with four additions (effect, effects, A ! F + G, forward) and writes plain Goose on the same lines. A resumable fn is cut at each operation of a once or many effect into a state machine whose frame is one struct. A handler dropping the rest is return E from f, a jump.

Zig

Zig passes what a function needs as a value, as it does Allocator. A context is a tuple of handlers known at compile time, and an operation is a call the compiler inlines. A type is a call the compiler evaluates, so a row is Row(.{ F, G }) and a missing effect is a compile error with its own message. A guard that may refuse an operation makes that effect's operations answer an error union, so the program says try and the types show which operations may be refused. The machine takes steps in place of closures: each a function declared once and named. A union is copied by value, which is what a resumable program needs; the states are written by hand.

TypeScript

A union type is a row: an effect is a tag with a name, and run() is present only when the union is empty. A generator is the idiom, and a generator's state cannot be copied, so the third parameter of Eff<A, E, boolean> records whether a program may be resumed many times. Types are erased: the guarantees hold for code without casts, and at run time a generator resumed twice fails with ResumedTwice.

Python

Python has no rows. A program is a generator, typed by what each operation answers under mypy --strict; its effects are the capabilities it is given. A generator cannot be copied, so a program that a handler resumes many times is written as data, as in TypeScript; one machine runs both. The business code stays a generator under asyncio: run_async awaits at the top.

Lean

An effect is an inductive family indexed by the answer's type, so dependent pattern matching tells a handler that an operation is its own, with no cast. The monad laws and what each standard handler makes of its operations are theorems; there is no sorry. The limit is stated in the README: the theorems are about each interpreter's reference definition, and what runs is a second definition, unsafe and not proved equal to the first.

Stack, asynchrony, interception

StackWaiting on the worldControl and audit of effects
okay-java An explicit stack on the heap; the tests run under -Xss512k Async: CompletableFuture, virtual threads In okay.rows, with okay-effects' Java names: Audit.audit with an Interceptor, K.after, Effects.observe, Observer.observe of every effect, std.Trail; a sensitive effect only under its audit. A program of the capability notation gets them through the Bridge
okay-direct Constant for handlers that answer in place Async: structured concurrency, a virtual clock, channels Interceptor, Audited, Observer
okay-effects, Java and Rust Constant: one loop, frames on the heap Async; in Rust time is a queue the caller runs intercept, observe, an audit trail, k.after; a sensitive effect only under its audit, refused by javac and rustc anywhere else
okay-kotlin Constant for deep handlers (its README) Runs inside kotlinx.coroutines as any suspend code intercepted, audit with a Vault; a KSP generator
okay-rust tail_rec for loops; the machine's stack is on the heap Step::Wait: a future, on any executor Audited, Policies, observe; a sensitive effect only under its audit
okay-go Go's own; prog: a million binds in constant stack All, Par, Race on goroutines Middleware over a program handed out to a host
okay-goose A resume last in a clause is a loop — A wrapper of a context with forward; sensitive effects are not there yet
okay-zig The machine frees each node as it is read and reuses frames On the wire, a direct-style call is a task of the worker's Io cx.observe, cx.guard
okay-ts Constant: a million mutual calls wait(promise), runPromise, cancellation audit, intercept, observe; a sensitive effect only under its audit
okay-python Data programs: 100 000 binds at Python's default recursion limit (its tests) run_async, all_of, race on asyncio Middleware over a program handed out to a host
okay-lean 108 operations on an 8 MB stack — intercept, around, observe, an audit trail; a sensitive effect only under its audit, a program reaching it otherwise refused by Lean. Laws proved: a passing interceptor is none, an observer is unseen, the trail of one path is its operations in order

Speed. Three repositories measure the same lane, every path of a choice among 1000, on a rest compiled to a state machine: okay-rust 0.28 µs a run (resumable/benches/lanes.rs, medians of three rounds, 28 Oct 2026), okay-zig 0.38 µs (zig build lanes -Doptimize=ReleaseFast), okay-goose 0.40 µs (bench/results.md, medians of 3–5 rounds, 28 Oct 2026). Each number is its repository's own measurement, from its own run; they were not measured together. The other repositories keep their own tables in their READMEs.

One meaning

One number is shared by four of the repositories on this page. Other suites are carried from repository to repository by hand. Some implementations are held to neither.

The family's TCK

The TCK is in okay-kernel (tck/Tck.scala): a thousand random programs, with handlers of logs, states, failures and choices nested in any order and each effect under two identities. Their outcomes are folded into one number, -8623788747993822161, the digest of okay-kernel's reference machine.

Comes to the digestWhereWhat is held to it
okay-java okay-kernel, integration: TestTckOnJava; okay-java, src/test/java/okay/rows/Tck.java okay-java as an implementation of okay-kernel's Java API (okay.core.Kernel). The TCK runs there on okay-core, okay-java and the reference machine in one process, each nesting through the others. And the row notation, okay.rows, by okay-effects' Java TCK, copied.
okay-rust machine/tests/tck.rs The crate okay-machine. Not the crate okay, and not okay-resumable.
okay-zig test/tck_test.zig The machine. Not the contexts.
okay-effects java/test/…/Tck.java, rust/tests/tck.rs, and the Scala kernel's Each of the three kernels.

The ports generate the programs themselves and compare with the constant; the reference machine is in okay-kernel only. okay-direct, okay-kotlin, okay-go, okay-goose, okay-ts, okay-python and okay-lean do not run this TCK. okay-ts lists it as its next step.

Suites carried over

Held to
okay-rust okay-core's suites, each test named after the one it ports (tests/std.rs is TestStd, tests/acceptance.rs TestAcceptance, tests/intercept.rs TestIntercept), and a reference interpreter on random programs. These are the machine's. The crate okay runs the interception programs again and compares the trails (tests/typed_intercept.rs).
okay-ts The same three suites of okay-core, the same programs and values (test/std.test.ts, test/acceptance.test.ts, test/intercept.test.ts).
okay-effects The promises of its README as tests, named alike in each language (Properties), and programs that must not compile, in Java, Rust and Scala.
okay-direct Its own TCK, the artifact okay-direct-tck: all three implementations pass it, Espresso the multi-shot one too.
okay-kotlin Its own: EffectsTck and RenamingTck hold both engines of the data style to the same answers. SpecTest runs the calculi of Forster, Kammar, Lindley and Pretnar (ICFP 2017) as written there.
okay-java In okay.rows: okay-effects' Java Properties and Audits, and its programs that javac must refuse, copied with only their package changed (PropertiesTest, NegativeTest).
okay-lean Proofs of the laws. Its specification is okay-simple's Free; its tests of interception run okay-simple's interception programs (Tests/InterceptTests.lean).
okay-go, okay-python, okay-goose Their own tests. okay-goose compares the output of its examples with files kept beside them (tests/run.sh).

So the direct-style implementations are not held to the digest: it is a test of programs as data. And nothing shared checks okay-go, okay-python or okay-goose except what they do on a wire with another language, below.

Working together

In one process, through okay-kernel's protocol. Between processes, on the okay wire.

In one process

okay-kernel is a protocol with its API in plain Java, no dependency: a program handed out steps to Done, Yield (an operation and its k, multi-shot), Failed or Cancelled. okay-java implements it with no wrapper: an Eff is the protocol's program, so its programs run under okay-core's handlers and okay-core's under its. okay-ts has the same steps, and okay-kernel's module js exports the protocol from Scala.js; test/kernel.test.ts runs programs both ways, and is skipped where that module is not built. okay-go, okay-python and the crate okay of okay-rust hand a program out to a host in the same shape (step, resume, fail, cancel), each in its own language.

The okay wire

The wire is the protocol of the okay platform: a far side (a worker) serves functions and programs by name, a host asks and answers the programs' operations under its own handlers, and may continue the same rest many times. Its specification is a transcript, okay-py/src/main/resources/okay/py/wire.txt. The platform has the host and its own far-side libraries for Python, R, TypeScript, Go, Rust and Haskell; Clojure, Frege and Java programs are walked inside the JVM (docs/foreign-languages.md).

Far sideHostChecked by, in its own repository
okay-effects Yes, in Scala, Java and Rust Yes, in all three Every worker against six transcripts, every host with every worker: nine pairs. A part of the wire; wire/README.md lists what is left out.
okay-zig Yes: a child's pipes, or the host's process through a C ABI No okay's WireConformance, in full over pipes (its README; conformance/TestZigLinks.scala)
okay-lean Yes: pipes, or the JVM's process through FFM Yes okay's WireConformance over pipes and FFM (conformance/TestLeanLinks.scala). Not served: direct style, streams, CBOR and compression.
okay-ts Yes: pipes, TCP, a WebSocket No test/wire.test.ts: the transcript's requests and answers, multi-shot, a condition, over TCP
okay-rust, okay-go, okay-python No transport of their own. An operation crosses as its name and a record of its fields, through okay's worker for that language; a handler of theirs can answer the other side's operations. One test each against okay's JVM host: examples/okayhost/TestOkayRustWire.scala, TestOkayGoWire.scala, TestOkayPythonWire.scala
okay-goose Lines of JSON on standard input and output, with okay-rust on the other side: a Goose program answered by Rust handlers, a resumable function's stops answered by Rust, and a Rust program answered by Goose. hosts/rust, tests/wire
okay-java, okay-direct, okay-kotlin NoNo—

Checked against each other

okay-effects keeps a script, wire/family/check.sh, that runs its host and workers against the sibling repositories. Its README records one verification, on 10 November 2026, run twice: 130 passed, 0 failed, 4 skipped. What it records as checked:

HostFar sideWhat
okay-effects, Scalaokay-zig's worker okay's conformance module: multi-shot, direct style, a condition, a held value, mux, streams under credit, an early stop, a duplex stream of 20 000 rows
okay-effects, Scalaokay-lean's worker What Lean serves of the same module: multi-shot, a condition, a held value
okay-effects, Scalaokay-ts, its own serveStdio Multi-shot, a program as a generator, a condition
okay-effects, Scalaokay's reference Python shim In JSON, CBOR and both with DEFLATE: calls, held objects, multi-shot, direct style, a condition; and wire.txt, every line as written
okay's wire.txt, line by lineokay-effects' Scala, Java and Rust workers Every section of the transcript but the table call
okay's own hostokay-effects' Scala, Java and Rust workers okay-effects' demonstration module: calls, held objects, multi-shot, mux, streams, a cancel, CBOR and DEFLATE, auth

The same README lists what was not verified: okay's WireConformance suite on okay-effects' workers; okay's Rust crate as a far side (one of the four skips); okay's Go, Haskell and R far sides; okay-effects' Java and Rust hosts with the family's far sides; other machines than one, macOS on arm64. okay-rust, okay-go, okay-python and okay-goose are not part of that check.