OSS updates March and April 2026

In this post I'll give updates about open source I worked on during March and April 2026.

To see previous OSS updates, go here.

Sponsors

I'd like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn't exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.

gratitude

Current top tier sponsors:

Open the details section for more info about sponsoring.

Sponsor info

If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!

Updates

Babashka conf and Dutch Clojure Days 2026

Babashka Conf 2026 is happening on May 8th in the OBA Oosterdok library in Amsterdam! David Nolen, primary maintainer of ClojureScript, will be our keynote speaker. We're excited to have Nubank, Exoscale, Bob, Flexiana and Itonomi as sponsors. Nubank and Exoscale are hiring. Wendy Randolph will be our event host. For the schedule and other info, see babashka.org/conf. Join the babashka-conf Slack channel on Clojurians Slack for last minute communication. The day after babashka conf, Dutch Clojure Days 2026 will be happening, so you can enjoy a whole weekend of Clojure in Amsterdam. Hope to see many of you there!

Projects

In the last two months I spent significant time organizing babashka conf, but made progress in several projects as well.

My upstream work to enable async/await in ClojureScript was merged in the beginning of March. The implementation mirrors squint. Thanks David for reviewing and merging. Also deftest now supports an ^:async annotation so you can use async/await and don't need to mess around with the cljs.test/async macro anymore:

I'll be presenting this work at the Dutch Clojure Days.

Rebel-readline is now bb compatible. The work involved mainly exposing more JLine stuff and making sure rebel-readline didn't hit any internal JLine APIs. One step to drive this to completion was to make a dependency, compliment, bb compatible. Thanks both to Bruce and Alexander for the cooperation.

Squint now supports cljs.test and multimethods! clojure-mode was ported to use the new cljs.test.

On the cream front, I put in effort to make the binary smaller and have been keeping up with the new GraalVM EA releases. I've been posting bug reports to the crema maintainer. Currently there's still an unfixed bug around core.async that I have trouble reproducing in pure Java. I also added lots of library tests to CI so I can ensure stability in the long run. For now it remains experimental, but the direction is promising.

A performance PR to weavejester/dependency speeds up depend, depends? and topo-sort significantly, so clerk notebooks render faster.

The cljfmt library, also by @weavejester, now fully runs from source in babashka. The Java diff library that wasn't bb-compatible was replaced with text-diff, but only for the babashka path. The JVM build of cljfmt still uses the original Java diff library, with a possible switch later once text-diff has matured.

Several SCI fixes were made to improve Clojure compatibility between babashka and Clojure. E.g. records can now support extending to IFn which was a blocker for some Clojure libs that tried to run in bb so far.

Clj-kondo 2026.04.15 got a few new linters thanks to @jramosg for stewarding most of these. It also has better out of the box potemkin support, and @alexander-yakushev contributed a wave of performance improvements.

Updates per project below. Bullets are highlights; see each project's CHANGELOG.md for the full list.

  • babashka: native, fast starting Clojure interpreter for scripting.

    • Released 1.12.216, 1.12.217 and 1.12.218
    • Support rebel-readline as external REPL provider:
      • Add proxy support for Completer, Highlighter, ParsedLine, Writer, Reader
      • Add clojure.repl/special-doc and clojure.repl/set-break-handler!
      • Add clojure.main/repl-read
      • Add org.jline.reader.Buffer to class allowlist
    • Add clojure.java.javadoc namespace with javadoc available in REPL #1933
    • Fix (doc var), (doc set!) and other special forms #1932
    • Support (source inc) and (source babashka.fs/exists?) for built-in vars #1935
    • Support BABASHKA_REPL_HISTORY env var for configurable REPL history location #1930
    • Fix deftype and defrecord inside non-top-level forms (e.g. let, testing) #1936
    • #1948: add java.util.HexFormat interop support
    • #1403: fix uberscript warnings with :as-alias
    • #1955: support -version as an alias for --version
    • #1954: add clojure.lang.EdnReader$ReaderException
    • #1951: fix --prepare flag skipping next token
    • #1967: expose clojure.data.xml.tree/{flatten-elements,event-tree}, clojure.data.xml.event record constructors, and clojure.data.xml.jvm.parse/string-source
    • #1969: include java.net.Proxy and java.net.Proxy$Type Java classes (@jeeger)
    • #1939: disable JLine backslash escaping/shell history commands (@bobisageek)
    • Performance improvements for math operations and for calling functions on locals
    • Add many new classes to reflection config: java.lang.reflect.Constructor, java.lang.reflect.Executable, java.util.stream.Collectors, java.util.Comparator (for reify), and more
    • Bump JLine to 4.0.12, cheshire to 6.2.0, nextjournal.markdown to 0.7.255, edamame to 1.5.39, data.xml to 0.2.0-alpha11, jsoup to 1.22.2, rewrite-clj to 1.2.54, tools.cli to 1.4.256, transit-clj to 1.1.357, fs to 0.5.32
    • Full changelog
  • SCI: Configurable Clojure/Script interpreter suitable for scripting

    • Fix recur with 20+ args in loop (#1035)
    • Check recur arity, throw when it doesn't match (#1034)
    • Support IFn on defrecord, deftype and reify (#808, #1036)
    • Validate single binding pair in let-like conditional macros (#1037)
    • Normalize SCI types in hierarchy lookups (#1033)
    • Expose IPrintWithWriter as protocol (#1032)
    • Optimize tight loops: fused binding nodes + specialized inlined calls (#1031)
    • Support special form documentation in doc macro
    • Include SCI types in ns-map
    • Full changelog
  • clj-kondo: static analyzer and linter for Clojure code that sparks joy.

    • Released 2026.04.15
    • #2788: NEW linter: :not-nil? which suggests (some? x) instead of (not (nil? x)), and similar patterns with when-not and if-not (default level: :off)
    • #2520: NEW linter: :protocol-method-arity-mismatch which warns when a protocol method is implemented with an arity that doesn't match any arity declared in the protocol (@jramosg)
    • #2520: NEW linter: :missing-protocol-method-arity (off by default) which warns when a protocol method is implemented but not all declared arities are covered
    • #2768: NEW linter: :redundant-declare which warns when declare is used after a var is already defined (@jramosg)
    • #1878: support potemkin's import-fn, import-macro, and import-def
    • #2498: support new potemkin import-vars :refer and :rename syntax
    • Performance optimizations across many linting paths (@alexander-yakushev) and hook-fn lookup caching to avoid repeated SCI evaluation
    • Add type support for pmap and future-related functions (future, future-call, future-done?, future-cancel, future-cancelled?) (@jramosg)
    • #2762: fix false positive: throw with string in CLJS no longer warns about type mismatch (@jramosg)
    • #2770: linter-specific ignores now correctly respect the specified linters
    • #2773: align executable path for images to be /bin/clj-kondo (@harryzcy)
    • #2621: load imports from symlinked config dir (@walterl)
    • #2798: report correct filename and error details when StackOverflowError occurs during analysis
    • Full changelog
  • cream: Clojure + GraalVM Crema native binary

    • Followed each GraalVM EA release: EA21 shrunk the binary to ~175MB, EA22 brought a virtual-thread fix, EA23 fixed the forkjoin segfault, EA24 finally allowed re-enabling clojure.core.async-test
    • Added smoke tests for httpkit, nextjournal/markdown, clj-yaml, core.async ioc-macros
    • Updated 10M loop benchmark numbers for EA21
    • Added Windows test status notes (still some failures on EA22)
  • squint: CLJS syntax to JS compiler

    • Released 0.10.186, 0.11.187, 0.11.188 and 0.11.189
    • Add multimethod support: defmulti, defmethod, get-method, methods, remove-method, remove-all-methods, prefer-method, prefers, plus hierarchy ops isa?, derive, underive, make-hierarchy, parents, ancestors, descendants (#806)
    • cljs.test/report is now a multimethod, extensible via defmethod. test-var now fires :begin-test-var / :end-test-var events.
    • Accept plain await in async functions, in anticipation of CLJS next. The legacy js-await and js/await forms continue to work as aliases for now.
    • Add built-in cljs.test / clojure.test support: deftest, is, testing, are, use-fixtures, async, run-tests
    • Fix with-meta now preserves callability when applied to a function
    • #783: auto-load macros from .cljc files via :require (no need for :require-macros); resolve qualified symbols from macro expansions
    • #784: resolve transitive macro deps and auto-import runtime deps from macro expansion
    • #809: add squint.compiler/compile* and squint.compiler/transpile* which accept either a string or a sequence of pre-parsed forms, skipping the forms -> string -> forms roundtrip for SSR use cases
    • #810: shorthand classes in #html / #jsx were erased when an attrs map was present without a :class key
    • Full changelog
  • cherry: Experimental ClojureScript to ES6 module compiler

    • Accept plain await as a special form, in anticipation of CLJS next
    • Multiple :require-macros clauses with :refer now properly accumulate instead of overwriting each other
    • Add cherry.test with clojure.test-compatible testing API: deftest, is, testing, are, use-fixtures, async, run-tests. Macros are compiler built-ins (shared with squint), so no :require-macros plumbing is needed in user code.
  • nbb: Scripting in Clojure on Node.js using SCI

    • Released 1.4.207
    • #408: support IFn on defrecord and reify
    • Fix REPL and nREPL not awaiting promesa thenables (e.g. p/then results)
  • fs: file system utility library for Clojure

    • Released 0.5.32 and 0.5.33
    • #232: add touch fn (@lread & @borkdude)
    • #197: docstring review: consistent arg naming, improved docstrings, added Coercions and Returns / Argument Naming Conventions sections to README (@lread)
    • #231: get/set attribute functions were never following links. They now respect the :nofollow-links option (@lread)
    • #254: fix split-ext and extension on dotfiles with parent dirs (e.g. foo/.gitignore)
    • #202: gzip & gunzip now honor dest dir when specified (@lread)
    • #215: document effect of umask on created files and directories (@lread)
    • #182: enable soft & hard link tests on Windows (@lread)
    • #242: test: add JDK 26 to CI test matrix (@lread)
  • clerk: Moldable Live Programming for Clojure

    • Improve analysis performance by bumping weavejester/dependency (#808)
    • Bump SCI to v0.12.51 (#793), enables async/await in viewer functions
    • Improve presentation performance (#803)
    • Remove bb-specific code for array-map data structure (#805)
    • Preserve TOC opts (#806)
    • Remove redundant declare of present+reset! (#809)
    • Fix build-graph crash on non-Clojure source files (#810)
  • edamame: configurable EDN and Clojure parser with location metadata and more

    • Released 1.5.38 and 1.5.39
    • parse-ns-form: include :use and :require-macros in :requires
    • Check if object is iobj before attaching metadata #141 #142
  • Nextjournal Markdown: A cross-platform Clojure/Script parser for Markdown

    • Released 0.7.225
    • Add option :disable-footnotes true to disable parsing footnotes #67
  • quickdoc: Quick and minimal API doc generation for Clojure

    • Released 0.2.6
    • #42: fix var name not recognized in docstring when preceded by multiline backtick expression
    • #52: fix formatting of function signature when :or destructuring uses namespaced keyword fallback value
    • Dedent indented docstrings before rendering #53
  • grasp: Grep Clojure code using clojure.spec regexes

    • Released 0.2.5
    • Bump SCI to 0.12.51, Clojure to 1.12.4
    • Upgrade CI to GraalVM 25; move Windows CI from Appveyor to GitHub Actions
    • Fix bug in native which dropped all match results (@bsless)
    • Fix circular reference in grasp.impl
  • babashka.nrepl: The nREPL server from babashka as a library

    • Lock output stream in send to prevent interleaved bencode frames from concurrent writes
    • info and lookup op refinements: lookup carries nested info map whereas info is a flatmap
  • pod-babashka-instaparse: instaparse from babashka

    • Expose add-line-and-column-info-to-metadata
    • Drop macOS Intel builds, now building for macOS aarch64 only
    • Migrate Windows CI from Appveyor to GitHub Actions
    • Upgrade CI to GraalVM 25
    • Add --features=clj_easy.graal_build_time.InitClojureClasses to native-image
  • instaparse-bb: Use instaparse from babashka

    • Released 0.0.7
    • Bump pod to 0.0.7
    • Add add-line-and-column-info-to-metadata and get-failure
    • Fix opts passing in parser (e.g. :output-format :enlive)
    • Support java.net.URL for grammars
  • babashka-sql-pods: babashka pods for SQL databases

    • Released 0.1.5 and 0.1.6
    • #74: add DB2 support (@janezj)
    • #72: handle concurrent requests (@katangafor)
    • Upgrade to Oracle GraalVM 25.0.2; bump next.jdbc, cheshire (Jackson 2.12 -> 2.20), PostgreSQL, MSSQL, HSQLDB, MySQL Connector/J drivers
    • Remove DuckDB support
    • #51: macOS binaries are now aarch64 only
  • http-client: HTTP client built on java.net.http

    • Replace defunct httpstat.us examples with httpbin.org in tests
  • neil: A CLI to add common aliases and features to deps.edn-based projects

    • Fix README instructions for dev installation (@teodorlu)
  • deps.clj: a faithful port of the clojure CLI bash script to Clojure

    • Released 1.12.4.1618
    • #145: support for installing in FreeBSD and Windows bash environments including MINGW64, MSYS_NT and Cygwin (@ikappaki)
    • Catch up with Clojure CLI 1.12.4.1618

Contributions to third party projects:

  • ClojureScript:
    • CLJS-3470: added async/await support (merged!)
    • CLJS-3476: added async deftest support (merged!)
  • weavejester/dependency: improve performance of depend, depends?, and topo-sort
  • weavejester/cljfmt: #404 babashka compatibility via new text-diff lib (merged!)
  • Engelberg/instaparse: submitted #242 for babashka compatibility. Required :bb reader conditionals to replace the AutoFlattenSeq deftype with plain vectors plus metadata markers, swap the Segment deftype for a reify-based CharSequence, and add a CI test runner. Open, awaiting review.

Other projects

These are (some of the) other projects I'm involved with but little to no activity happened in the past two months.

Click for more details - [scittle](https://github.com/babashka/scittle): Execute Clojure(Script) directly from browser script tags via SCI - [pod-babashka-go-sqlite3](https://github.com/babashka/pod-babashka-go-sqlite3): A babashka pod for interacting with sqlite3 - [unused-deps](https://github.com/borkdude/unused-deps): Find unused deps in a clojure project - [pod-babashka-fswatcher](https://github.com/babashka/pod-babashka-fswatcher): babashka filewatcher pod - [sci.nrepl](https://github.com/babashka/sci.nrepl): nREPL server for SCI projects that run in the browser - [babashka.nrepl-client](https://github.com/babashka/nrepl-client) - [http-server](https://github.com/babashka/http-server): serve static assets - [sci.configs](https://github.com/babashka/sci.configs): A collection of ready to be used SCI configs. - [html](https://github.com/borkdude/html): Html generation library inspired by squint's html tag - [rewrite-edn](https://github.com/borkdude/rewrite-edn): Utility lib on top of rewrite-clj - [rewrite-clj](https://github.com/clj-commons/rewrite-clj): Rewrite Clojure code and edn - [tools-deps-native](https://github.com/babashka/tools-deps-native) and [tools.bbuild](https://github.com/babashka/tools.bbuild): use tools.deps directly from babashka - [bbin](https://github.com/babashka/bbin): Install any Babashka script or project with one command - [qualify-methods](https://github.com/borkdude/qualify-methods) - Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only) - [tools](https://github.com/borkdude/tools): a set of [bbin](https://github.com/babashka/bbin/) installable scripts - [babashka.json](https://github.com/babashka/json): babashka JSON library/adapter - [speculative](https://github.com/borkdude/speculative) - [squint-macros](https://github.com/squint-cljs/squint-macros): a couple of macros that stand-in for [applied-science/js-interop](https://github.com/applied-science/js-interop) and [promesa](https://github.com/funcool/promesa) to make CLJS projects compatible with squint and/or cherry. - [lein-clj-kondo](https://github.com/clj-kondo/lein-clj-kondo): a leiningen plugin for clj-kondo - [http-kit](https://github.com/http-kit/http-kit): Simple, high-performance event-driven HTTP client+server for Clojure. - [jet](https://github.com/borkdude/jet): CLI to transform between JSON, EDN, YAML and Transit using Clojure - [lein2deps](https://github.com/borkdude/lein2deps): leiningen to deps.edn converter - [cljs-showcase](https://github.com/borkdude/cljs-showcase): Showcase CLJS libs using SCI - [babashka.book](https://github.com/babashka/book): Babashka manual - [pod-babashka-buddy](https://github.com/babashka/pod-babashka-buddy): A pod around buddy core (Cryptographic Api for Clojure). - [gh-release-artifact](https://github.com/borkdude/gh-release-artifact): Upload artifacts to Github releases idempotently - [carve](https://github.com/borkdude/carve) - Remove unused Clojure vars - [4ever-clojure](https://github.com/oxalorg/4ever-clojure) - Pure CLJS version of 4clojure, meant to run forever! - [pod-babashka-lanterna](https://github.com/babashka/pod-babashka-lanterna): Interact with clojure-lanterna from babashka - [joyride](https://github.com/BetterThanTomorrow/joyride): VSCode CLJS scripting and REPL (via [SCI](https://github.com/babashka/sci)) - [clj2el](https://borkdude.github.io/clj2el/): transpile Clojure to elisp - [deflet](https://github.com/borkdude/deflet): make let-expressions REPL-friendly! - [deps.add-lib](https://github.com/borkdude/deps.add-lib): Clojure 1.12's add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI - [CLI](https://github.com/babashka/cli): Turn Clojure functions into CLIs! - [quickblog](https://github.com/borkdude/quickblog): light-weight static blog engine for Clojure and babashka - [process](https://github.com/babashka/process): Clojure library for shelling out / spawning sub-processes - [parmezan](https://github.com/borkdude/parmezan): fixes unbalanced or unexpected parens or other delimiters in Clojure files - [reagami](https://github.com/borkdude/reagami): A minimal zero-deps Reagent-like for Squint and CLJS

Published: 2026-05-04

Tagged: clojure oss updates

OSS updates January and February 2026

In this post I'll give updates about open source I worked on during January and February 2026.

To see previous OSS updates, go here.

Sponsors

I'd like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn't exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.

gratitude

Current top tier sponsors:

Open the details section for more info about sponsoring.

Sponsor info

If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!

Updates

Babashka conf and Dutch Clojure Days 2026

Babashka Conf 2026 is happening on May 8th in the OBA Oosterdok library in Amsterdam! David Nolen, primary maintainer of ClojureScript, will be our keynote speaker! We're excited to have Nubank, Exoscale, Bob and Itonomi as sponsors. Wendy Randolph will be our event host / MC / speaker liaison :-). The CfP is now closed. More information here. Get your ticket via Meetup.com (there is a waiting list, but more places may become available). The day after babashka conf, Dutch Clojure Days 2026 will be happening, so you can enjoy a whole weekend of Clojure in Amsterdam. Hope to see many of you there!

Projects

I spent a lot of time making SCI's deftype, case, and macroexpand-1 match JVM Clojure more closely. As a result, libraries like riddley, cloverage, specter, editscript, and compliment now work in babashka.

After seeing charm.clj, a terminal UI library, I decided to incorporate JLine3 into babashka so people can build terminal UIs. The goal is to be able to run rebel-readline + nREPL from source in babashka, but this is still work in progress (e.g. the compliment PR is still pending). Since I had JLine anyway, babashka also got a major REPL upgrade with multi-line editing, tab completion, ghost text, and persistent history.

On the CLJS side, SCI, scittle, and nbb all gained async/await support.

Last but not least, I started cream, an experimental native binary that runs full JVM Clojure with fast startup using GraalVM's Crema. Unlike babashka, it supports runtime bytecode generation (definterface, deftype, gen-class). It currently depends on a fork of Clojure and GraalVM EA, so it's not production-ready yet.

Here are updates about the projects/libraries I've worked on in the last two months in detail.

  • NEW: cream: Clojure + GraalVM Crema native binary

    • A native binary that runs full JVM Clojure with fast startup, using GraalVM's Crema (RuntimeClassLoading) to enable runtime eval, require, and library loading
    • Unlike babashka, supports definterface, deftype, gen-class, and other constructs that generate JVM bytecode at runtime
    • Can run .java source files directly, as a fast alternative to JBang
    • Cross-platform: Linux, macOS, Windows
  • babashka: native, fast starting Clojure interpreter for scripting.

    • Released 1.12.214 and 1.12.215
    • #1909: add JLine3 for TUI support
    • Console REPL (bb repl) improvements: multi-line editing, tab completion, ghost text, eldoc, doc-at-point (C-x C-d), persistent history
    • Support deftype with map interfaces (e.g. IPersistentMap, ILookup, Associative). Libraries like core.cache and linked now work in babashka.
    • Compatibility with riddley, cloverage, editscript, charm.clj
    • #1299: add new babashka.terminal namespace that exposes tty?
    • Add keyword completions to nREPL and console REPL
    • deftype supports Object + hashCode
    • #1923: support reify with java.time.temporal.TemporalQuery
    • Fix reify with methods returning int/short/byte/float
    • Full changelog
  • SCI: Configurable Clojure/Script interpreter suitable for scripting

    • Released 0.12.51
    • deftype now macroexpands to deftype*, matching JVM Clojure, enabling code walkers like riddley
    • case now macroexpands to JVM-compatible case* format, enabling tools like riddley and cloverage
    • Support async/await in ClojureScript. See docs.
    • Support functional interface adaptation for instance targets
    • Infer type tags from let binding values to binding names
    • defrecord now expands to deftype* (like Clojure), with factory fns emitted directly in the macro expansion
    • macroexpand-1 now accepts an optional env map as first argument
    • Add proxy-super, proxy-call-with-super, update-proxy and proxy-mappings
    • Support #564: this-as in ClojureScript
    • Store current analysis context during macro invocation, enabling tools like riddley to access outer locals
    • Full changelog
  • clj-kondo: static analyzer and linter for Clojure code that sparks joy.
    @jramosg, @tomdl89 and @hugod have been on fire with contributions this period. Six new linters!

    • Released 2026.01.12 and 2026.01.19
    • #2735: NEW linter: :duplicate-refer which warns on duplicate entries in :refer of :require (@jramosg)
    • #2734: NEW linter: :aliased-referred-var, which warns when a var is both referred and accessed via an alias in the same namespace (@jramosg)
    • #2745: NEW linter: :is-message-not-string which warns when clojure.test/is receives a non-string message argument (@jramosg)
    • #2712: NEW linter: :redundant-format to warn when format strings contain no format specifiers (@jramosg)
    • #2709: NEW linter: :redundant-primitive-coercion to warn when primitive coercion functions are applied to expressions already of that type (@hugod)
    • Add new types array, class, inst and type checking support for related functions (@jramosg)
    • Add type checking support for clojure.test functions and macros (@jramosg)
    • #2340: Extend :condition-always-true linter to check first argument of clojure.test/is (@jramosg)
    • #2729: Check for arity mismatch for bound vectors, sets & maps, not just literals (@tomdl89)
    • #2768: NEW linter: :redundant-declare which warns when declare is used after a var is already defined (@jramosg)
    • Add type support for pmap and future-related functions (@jramosg)
    • Upgrade to GraalVM 25
    • Full changelog
  • squint: CLJS syntax to JS compiler @tonsky and @willcohen contributed several improvements this period.

    • Add squint.math, also available as clojure.math namespace
    • #779: Added compare-and-swap!, swap-vals! and reset-vals! (@tonsky)
    • #788: Fixed compilation of dotimes with _ binding (@tonsky)
    • #790: Fixed shuffle not working on lazy sequences (@tonsky)
    • Multiple :require-macros with :refer now accumulate instead of overwriting (@willcohen)
    • Fix emitting negative zero value (-0.0)
    • Fix #792: prn js/undefined as nil
    • Fix #793: fix yield* IIFE
    • Full changelog
  • scittle: Execute Clojure(Script) directly from browser script tags via SCI

    • Support async/await. See docs.
    • Implement js/import not using eval
    • Support this-as
    • nREPL: print #<Promise value> when a promise is evaluated
  • nbb: Scripting in Clojure on Node.js using SCI

    • Support async/await. See docs for syntax.
    • Print promise result value in REPL/nREPL: (js/Promise.resolve 1) ;;=> #<Promise 1>
  • fs - File system utility library for Clojure

    • Released 0.5.31
    • #212: Introduce :keep true option in with-temp-dir
    • #188 copy-tree now throws if src or dest is a symbolic link when not following links (@lread)
    • #201 gzip now accepts source-file Path (@lread)
    • #207 review and update glob and match docstrings (@lread)
  • clerk: Moldable Live Programming for Clojure

    • Fix browse when using random port by passing 0, fixes #801
    • bb now supports editscript
  • neil: A CLI to add common aliases and features to deps.edn-based projects.

    • #258: neil test now exits with non-zero exit code when tests fail
  • cherry: Experimental ClojureScript to ES6 module compiler

    • Multiple :require-macros clauses with :refer now properly accumulate instead of overwriting each other

Contributions to third party projects:

  • editscript: Added babashka support, deps.edn for git dep usage, fixed CLJS tests
  • riddley: Added babashka compatibility, clj-kondo config
  • cloverage: Added babashka compatibility, migrated tools.cli from deprecated cli/cli to cli/parse-opts, bumped riddley
  • specter: Added babashka compatibility
  • compliment: Added babashka compatibility (PR #131)
  • rebel-readline: Removed JLine impl class dependencies for babashka compatibility, released 0.1.7
  • Selmer: Namespaced script tag context keys to avoid collisions, removed runtime require of clojure.tools.logging
  • charm.clj: Contributed JLine integration, FFM native terminal interface, babashka and native-image compatibility

Other projects

These are (some of the) other projects I'm involved with but little to no activity happened in the past month.

Click for more details - [pod-babashka-go-sqlite3](https://github.com/babashka/pod-babashka-go-sqlite3): A babashka pod for interacting with sqlite3 - [unused-deps](https://github.com/borkdude/unused-deps): Find unused deps in a clojure project - [pod-babashka-fswatcher](https://github.com/babashka/pod-babashka-fswatcher): babashka filewatcher pod - [sci.nrepl](https://github.com/babashka/sci.nrepl): nREPL server for SCI projects that run in the browser - [babashka.nrepl-client](https://github.com/babashka/nrepl-client) - [http-server](https://github.com/babashka/http-server): serve static assets - [sci.configs](https://github.com/babashka/sci.configs): A collection of ready to be used SCI configs. - [http-client](https://github.com/babashka/http-client): babashka's http-client - [html](https://github.com/borkdude/html): Html generation library inspired by squint's html tag - [instaparse-bb](https://github.com/babashka/instaparse-bb): Use instaparse from babashka - [sql pods](https://github.com/babashka/babashka-sql-pods): babashka pods for SQL databases - [rewrite-edn](https://github.com/borkdude/rewrite-edn): Utility lib on top of - [rewrite-clj](https://github.com/clj-commons/rewrite-clj): Rewrite Clojure code and edn - [tools-deps-native](https://github.com/babashka/tools-deps-native) and [tools.bbuild](https://github.com/babashka/tools.bbuild): use tools.deps directly from babashka - [bbin](https://github.com/babashka/bbin): Install any Babashka script or project with one command - [qualify-methods](https://github.com/borkdude/qualify-methods) - Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only) - [tools](https://github.com/borkdude/tools): a set of [bbin](https://github.com/babashka/bbin/) installable scripts - [babashka.json](https://github.com/babashka/json): babashka JSON library/adapter - [speculative](https://github.com/borkdude/speculative) - [squint-macros](https://github.com/squint-cljs/squint-macros): a couple of macros that stand-in for [applied-science/js-interop](https://github.com/applied-science/js-interop) and [promesa](https://github.com/funcool/promesa) to make CLJS projects compatible with squint and/or cherry. - [grasp](https://github.com/borkdude/grasp): Grep Clojure code using clojure.spec regexes - [lein-clj-kondo](https://github.com/clj-kondo/lein-clj-kondo): a leiningen plugin for clj-kondo - [http-kit](https://github.com/http-kit/http-kit): Simple, high-performance event-driven HTTP client+server for Clojure. - [babashka.nrepl](https://github.com/babashka/babashka.nrepl): The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs - [jet](https://github.com/borkdude/jet): CLI to transform between JSON, EDN, YAML and Transit using Clojure - [lein2deps](https://github.com/borkdude/lein2deps): leiningen to deps.edn converter - [cljs-showcase](https://github.com/borkdude/cljs-showcase): Showcase CLJS libs using SCI - [babashka.book](https://github.com/babashka/book): Babashka manual - [pod-babashka-buddy](https://github.com/babashka/pod-babashka-buddy): A pod around buddy core (Cryptographic Api for Clojure). - [gh-release-artifact](https://github.com/borkdude/gh-release-artifact): Upload artifacts to Github releases idempotently - [carve](https://github.com/borkdude/carve) - Remove unused Clojure vars - [4ever-clojure](https://github.com/oxalorg/4ever-clojure) - Pure CLJS version of 4clojure, meant to run forever! - [pod-babashka-lanterna](https://github.com/babashka/pod-babashka-lanterna): Interact with clojure-lanterna from babashka - [joyride](https://github.com/BetterThanTomorrow/joyride): VSCode CLJS scripting and REPL (via [SCI](https://github.com/babashka/sci)) - [clj2el](https://borkdude.github.io/clj2el/): transpile Clojure to elisp - [deflet](https://github.com/borkdude/deflet): make let-expressions REPL-friendly! - [deps.add-lib](https://github.com/borkdude/deps.add-lib): Clojure 1.12's add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI - [edamame](https://github.com/borkdude/edamame): configurable EDN and Clojure parser with location metadata and more - [CLI](https://github.com/babashka/cli): Turn Clojure functions into CLIs! - [quickblog](https://github.com/borkdude/quickblog): light-weight static blog engine for Clojure and babashka - [process](https://github.com/babashka/process): Clojure library for shelling out / spawning sub-processes - [deps.clj](https://github.com/borkdude/deps.clj): A faithful port of the clojure CLI bash script to Clojure - [reagami](https://github.com/borkdude/reagami): A minimal zero-deps Reagent-like for Squint and CLJS - [parmezan](https://github.com/borkdude/parmezan): fixes unbalanced or unexpected parens or other delimiters in Clojure files - [quickdoc](https://github.com/borkdude/quickdoc): Quick and minimal API doc generation for Clojure - [Nextjournal Markdown](https://github.com/nextjournal/markdown)

Published: 2026-03-05

Tagged: clojure oss updates

Babashka 1.12.215: Revenge of the TUIs

Babashka is a fast-starting native Clojure scripting runtime. It uses SCI to interpret Clojure and compiles to a native binary via GraalVM, giving you Clojure's power with near-instant startup. It's commonly used for shell scripting, build tooling, and small CLI applications. If you don't yet have bb installed, you can with brew:

brew install borkdude/brew/babashka

or bash:

bash <(curl -s https://raw.githubusercontent.com/babashka/babashka/master/install)

This release is, in my opinion, a game changer. With JLine3 bundled, you can now build full terminal user interfaces in babashka. The bb repl has been completely overhauled with multi-line editing, completions, and eldoc. deftype now supports map interfaces, making bb more compatible with existing libraries like core.cache. SCI has had many small improvements, making riddley compatible too. Riddley is used in Cloverage, a code coverage library for Clojure, which now also works with babashka (Cloverage PR pending).

Babashka conf 2026

But first, let me mention an exciting upcoming event! Babashka conf is happening again for the second time! The first time was 2023 in Berlin. This time it's in Amsterdam. The Call for Proposals is open until the end of February, so there is still time to submit your talk or workshop. We are also looking for one last gold sponsor (500 euros) to cover all costs.

Highlights

JLine3 and TUI support

Babashka now bundles JLine3, a Java library for building interactive terminal applications. You get terminals, line readers with history and tab completion, styled output, keyboard bindings, and the ability to reify custom completers, parsers, and widgets — all from bb scripts.

JLine3 works on all platforms, including Windows PowerShell and cmd.exe.

Here's a simple interactive prompt that reads lines from the user until EOF (Ctrl+D):

(import '[org.jline.terminal TerminalBuilder]
        '[org.jline.reader LineReaderBuilder])

(let [terminal (-> (TerminalBuilder/builder) (.build))
      reader   (-> (LineReaderBuilder/builder)
                   (.terminal terminal)
                   (.build))]
  (try
    (loop []
      (when-let [line (.readLine reader "prompt> ")]
        (println "You typed:" line)
        (recur)))
    (catch org.jline.reader.EndOfFileException _
      (println "Goodbye!"))
    (finally
      (.close terminal))))

babashka.terminal namespace

A new babashka.terminal namespace exposes a tty? function to detect whether stdin, stdout, or stderr is connected to a terminal:

(require '[babashka.terminal :refer [tty?]])

(when (tty? :stdout)
  (println "Interactive terminal detected, enabling colors"))

This accepts :stdin, :stdout, or :stderr as argument. It uses JLine3's terminal provider under the hood.

This is useful for scripts that want to behave differently when piped vs. run interactively, for example enabling colored output or progress bars only in a terminal.

charm.clj compatibility

charm.clj is a new Clojure library for building terminal user interfaces using the Elm architecture (Model-Update-View). It provides components like spinners, text inputs, lists, paginators, and progress bars, with support for ANSI/256/true color styling and keyboard/mouse input handling.

charm.clj is now compatible with babashka (or rather, babashka is now compatible with charm.clj), enabled by the combination of JLine3 support and other interpreter improvements in this release. This means you can build rich TUI applications that start instantly as native binaries.

Here's a complete counter example you can save as a single file and run with bb:

#!/usr/bin/env bb

(babashka.deps/add-deps
 '{:deps {io.github.TimoKramer/charm.clj {:git/sha "cf7a6c2fcfcccc44fcf04996e264183aa49a70d6"}}})

(require '[charm.core :as charm])

(def title-style
  (charm/style :fg charm/magenta :bold true))

(def count-style
  (charm/style :fg charm/cyan
               :padding [0 1]
               :border charm/rounded-border))

(defn update-fn [state msg]
  (cond
    (or (charm/key-match? msg "q")
        (charm/key-match? msg "ctrl+c"))
    [state charm/quit-cmd]

    (or (charm/key-match? msg "k")
        (charm/key-match? msg :up))
    [(update state :count inc) nil]

    (or (charm/key-match? msg "j")
        (charm/key-match? msg :down))
    [(update state :count dec) nil]

    :else
    [state nil]))

(defn view [state]
  (str (charm/render title-style "Counter App") "\n\n"
       (charm/render count-style (str (:count state))) "\n\n"
       "j/k or arrows to change\n"
       "q to quit"))

(charm/run {:init {:count 0}
            :update update-fn
            :view view
            :alt-screen true})
charm.clj counter example running in babashka

More examples can be found here.

Deftype with map interfaces

Until now, deftype in babashka couldn't implement JVM interfaces like IPersistentMap, ILookup, or Associative. This meant libraries that define custom map-like types, a very common Clojure pattern, couldn't work in babashka.

Starting with this release, deftype supports map interfaces. Your deftype must declare IPersistentMap to signal that you want a full map type. Other map-related interfaces like ILookup, Associative, Counted, Seqable, and Iterable are accepted freely since the underlying class already implements them.

This unlocks several libraries that were previously incompatible:

  • core.cache: all cache types (BasicCache, FIFOCache, LRUCache, TTLCache, LUCache) work unmodified
  • linked: insertion-ordered maps and sets

Riddley and Cloverage compatibility

Riddley is a Clojure library for code walking that many other libraries depend on. Previously, SCI's deftype and case did not macroexpand to the same special forms as JVM Clojure, which broke riddley's walker. Several changes now align SCI's behavior with Clojure: deftype macroexpands to deftype*, case to case*, and macroexpand-1 now accepts an optional env map as second argument (inspired by how the CLJS analyzer API works). Together these changes enable riddley and tools built on it, like cloverage and Specter, to work with bb.

Riddley has moved to clj-commons, thanks to Zach Tellman for transferring it. I'd like to thank Zach for all his contributions to the Clojure community over the years. Version 0.2.2 includes bb compatibility, which was one of the first PRs merged after the transfer. Cloverage compatibility has been submitted upstream, all 75 cloverage tests pass on both JVM and babashka.

Console REPL improvements

The bb repl experience has been significantly improved with JLine3 integration. You no longer need rlwrap to get a comfortable console REPL:

  • Multi-line editing: the REPL detects incomplete forms and continues reading on the next line with a #_=> continuation prompt
  • Tab completion: Clojure-aware completions powered by SCI, including keywords (:foo, ::foo, ::alias/foo)
Tab completions in bb repl
  • Ghost text: as you type, the common completion prefix appears as faint inline text after the cursor. Press TAB to accept.
Ghost text in bb repl
  • Eldoc: automatic argument help — when your cursor is inside a function call like (map |), the arglists are displayed below the prompt
  • Doc-at-point: press Ctrl+X Ctrl+D to show full documentation for the symbol at the cursor
  • Persistent history: command history saved across sessions in ~/.bb_repl_history
  • Ctrl+C handling: first press on an empty prompt warns, second press exits

Many of these features were inspired by rebel-readline, Leiningen's REPL, and Node.js's REPL.

SCI improvements

Under the hood, SCI (the interpreter powering babashka) received many improvements in this cycle:

  • Functional interface adaptation for instance targets: you can now write (let [^Predicate p even?] (.test p 42)) and SCI will adapt the Clojure function to the functional interface automatically.
  • Type tag inference: SCI now infers type tags from let binding values to binding names, reducing the need for explicit type hints in interop-heavy code.
  • Several bug fixes: read with nil/false as eof-value, letfn with duplicate function names, ns-map not reflecting shadowed vars, NPE in resolve, and .method on class objects routing incorrectly.

Other improvements

  • Support multiple catch clauses in combination with ^:sci/error
  • Fix satisfies? on protocols with proxy
  • Support reify with java.time.temporal.TemporalQuery
  • Fix reify with methods returning int/short/byte/float primitives
  • nREPL server now uses non-daemon threads so the process stays alive without @(promise)
  • Add clojure.test.junit as built-in source namespace
  • Add cp437 (IBM437) charset support in native binary via selective GraalVM charset Feature, avoiding the ~5MB binary size increase from AddAllCharsets. More charsets can be added on request.

For the full list of changes including new Java classes and library bumps, see the changelog.

Thanks

Thank you to all the contributors who helped make this release possible. Special thanks to everyone who reported issues, tested pre-release builds from babashka-dev-builds, and provided feedback.

Thanks to Clojurists Together and all babashka sponsors and contributors for their ongoing support. Your sponsorship makes it possible to keep developing babashka.

And thanks to all babashka users: you make this project what it is. Happy scripting!

Published: 2026-02-17

Tagged: clojure babashka

Archive