Champaca compared with babashka

Both run Java-flavoured work without starting a JVM, but they're built almost inside out from each other. Babashka is a Clojure interpreter, SCI, that GraalVM's native-image compiled ahead of time into one binary along with a selection of Java classes. Your Clojure is interpreted there, and the Java it can reach was chosen when babashka was built. Champaca is a Java runtime inside jolt. It loads class files at run time, turns each method's bytecode into Chez Scheme the first time it's called and compiles that to native code in the same process, so your Clojure is jolt's, compiled natively, and the Java it calls is compiled on demand.

Babashka (native-image and SCI)Champaca (jolt and Chez, after OpenLDK)
What runs your ClojureSCI, which runs it form by form without compiling itjolt, which compiles it to native code through Chez
What runs the JavaClasses native-image compiled into the binaryThe JDK's own class files, read from $JAVA_HOME/lib/modules, and your jars, translated method by method
Which Java classes there areA pre-selected set; you can't add classes at run timeAny class file: the whole JDK, the class path, and classes made at run time (defineClass, proxies, hidden classes)
When Java code is compiledBefore release, on the build machineAt run time, the first time each method is called
Where Java objects liveThe native image's heap; Clojure's data types are the same as on the JVMChez records in jolt's own heap
How the JDK startsWhatever native-image prepared at build timeThe JDK's own boot, as HotSpot runs it, module system included (how-it-works)
StartupFast, with nothing left to compileA first Hello takes 4.3 s, a warm one 0.39 s on an M1 Pro, from the startup cache (performance)
ThreadsRun in parallel (pmap, future)Real threads, but one lock lets one run Java at a time (limitations)
Clojure it lacksSCI is a subset: no deftype, definterface or unboxed math, defprotocol and defrecord emulated with multimethods and maps, reify of one class at a timeWhatever jolt lacks; champaca adds no limits of its own
Adding capabilityA new babashka build with more classes, or a podA jar on the class path
Statusclojure.core and java.lang support is stable, by its READMEExperimental, checked along its tests and the twenty-three libraries jolt libs runs

The babashka column comes from its README's "Differences with Clojure" and "Setting expectations" sections (at b429a12e).

What that means in practice

Babashka starts instantly and runs the Java it shipped with at native speed. Its own Clojure goes through an interpreter, though, which is why its README sends a script that runs for more than a few seconds, or loops a lot, to Clojure on the JVM. And a Java class outside its set isn't there at all.

Champaca runs libraries unchanged: Jackson, Guava, Guice, H2, Byte Buddy and the rest of what jolt libs checks, with the same output as HotSpot. Once a method is compiled it runs as native Chez code with inline caches, and jolt code calls it as a plain procedure call.

Champaca's costs are a slow first run, which the startup cache softens much as class data sharing does for HotSpot, Java code that can't run on two threads at once, and warm runs slower than the JVM's for library-heavy code. A warm Jackson run takes 1.34 s against 0.28 s on the JVM (performance).

At the boundary, babashka's Clojure data and Java objects are the same JVM objects. Champaca's Java objects are Chez records, apart from jolt's own values, so data crossing between them is converted on the way (data-conversion).