A big phat clj-kondo release just before 🎄 !
https://github.com/clj-kondo/clj-kondo: static analyzer and linter for Clojure code that sparks joy ✨
2025.12.23
• https://github.com/clj-kondo/clj-kondo/issues/2654: NEW linter: redundant-let-binding, defaults to :off (https://github.com/tomdl89)
• https://github.com/clj-kondo/clj-kondo/issues/2653: NEW linter: :unquote-not-syntax-quoted to warn on ~ and ~@ usage outside syntax-quote (```) (https://github.com/jramosg)
• https://github.com/clj-kondo/clj-kondo/issues/2613: NEW linter: :refer-clojure-exclude-unresolved-var to warn on non-existing vars in :refer-clojure :exclude (https://github.com/jramosg)
• https://github.com/clj-kondo/clj-kondo/issues/2668: Lint & syntax errors in let bindings and lint for trailing & (https://github.com/tomdl89)
• Fix https://github.com/clj-kondo/clj-kondo/issues/2687: support new :refer-global and :require-global ns options in CLJS
• https://github.com/clj-kondo/clj-kondo/issues/2590: duplicate-key-in-assoc changed to duplicate-key-args, and now lints dissoc, assoc! and dissoc! too (https://github.com/tomdl89)
• https://github.com/clj-kondo/clj-kondo/issues/2651: resume linting after paren mismatches
• https://github.com/clojure-lsp/clojure-lsp/issues/2157: Fix inner class name for java-class-definitions.
• https://github.com/clojure-lsp/clojure-lsp/issues/2157: Include inner class java-class-definition analysis.
• Bump babashka/fs
• https://github.com/clj-kondo/clj-kondo/issues/2532: Disable :duplicate-require in require + :reload / :reload-all
• https://github.com/clj-kondo/clj-kondo/issues/2432: Don't warn for :redundant-fn-wrapper in case of inlined function
• https://github.com/clj-kondo/clj-kondo/issues/2599: detect invalid arity for invoking collection as higher order function
• https://github.com/clj-kondo/clj-kondo/issues/2661: Fix false positive :unexpected-recur when recur is used inside clojure.core.match/match (https://github.com/jramosg)
• https://github.com/clj-kondo/clj-kondo/issues/2617: Add types for repeatedly (https://github.com/jramosg)
• Add :ratio type support for numerator and denominator functions (https://github.com/jramosg)
• https://github.com/clj-kondo/clj-kondo/issues/2676: Report unresolved namespace for namespaced maps with unknown aliases (https://github.com/jramosg)
• https://github.com/clj-kondo/clj-kondo/issues/2683: data argument of ex-info may be nil since clojure 1.12
• Bump built-in ClojureScript analysis info
• Fix https://github.com/clj-kondo/clj-kondo/issues/2544: support inline configs in .cljc files
Thanks to all contributors, users and sponsors! clojurists-together github-dark gratitude
I am thrilled, and very nervous, to announce calva Calva https://github.com/BetterThanTomorrow/calva/releases/tag/v2.0.543. This release makes Calva support connecting and managing arbitrary many Clojure REPLs of whatever kind, plugging a glaring hole in Calva’s REPL session management (if the previous way could even be called that).
• Demo video here: https://www.youtube.com/watch?v=36dTtyfa_OY
Changes:
• https://github.com/BetterThanTomorrow/calva/issues/76
◦ Connecting an additional sequence no longer disconnects earlier ones unless they reuse the same replSessionNames (treated as a re-connect).
◦ Jacking in to another connect sequence no longer closes the previous REPL; each jack-in keeps its own pseudo terminal unless the sessions share replSessionNames, in which case it becomes a restart.
◦ Auto-routes files to sessions with replSessionFilePatterns using primary/`secondary` keys. Patterns like *.clj are automatically scoped to the sequence’s project root.
◦ New command: Calva: Repl Sessions, listing sessions, enabling pinning, toggling auto-route, and selecting the CLJC evaluation session (also available from the status bar session indicator).
◦ Add a REPL Sessions status bar menu for pinning sessions, toggling auto-route, and setting .cljc overrides.
◦ Updates to https://calva.io/connect-sequences/:
◦ Custom REPL session names via replSessionNames: primary (defaults to clj) and secondary (defaults to cljs).
◦ Pattern tier properties always-claim/`is-fallback-for` control routing priority. The always-claim tier takes precedence in file routing.
◦ Rename afterCLJReplJackInCode → afterPrimaryReplConnectedCode (the old name still works).
◦ Automatic session name conflict resolution: connecting multiple REPLs with the same session names (e.g., two deps.edn projects) “just works”. Calva appends a suffix from the pool e.g., clj:2, cljs:2, to avoid conflicts, preserving names on reconnection.
◦ Allows Session pinning—lock all evaluations to a specific session and override pattern-based routing.
◦ Adds API function repl.listSessions()
◦ Updates default connect sequences for Joyride, Babashka, nbb, and Basilisp, to use custom replSessionNames, and configured default routings with replSessionFilePatterns.
◦ Removed deprecated calva.useLegacyReplWindowPath setting. The REPL window is now always located at .calva/repl.calva-repl.
◦ Let the first session connected determine where the REPL Window file is created.
• Adds a new connect sequence: Clojure projectless, for jack-in and connect without a deps.edn, etcetera needed.
• Improve error messages around CLJS build configuration
• Adds https://github.com/babashka/scittle connect sequence
• Adds defaultPort to connect sequence settings.
• The calva.copyJackInCommandToClipboard command now accepts a connect sequence argument.
• Add some messaging when using the REPL Window, and when potentially attempting to use it from the wrong .calva-repl file.
Why not fixed until now? Support for multiple sessions was among the first 100 issues ever filed on Calva, seven years ago. At the time I didn’t understand the issue at all (I only had a very vague idea about what a Clojure REPL is). And during the years it has simply looked like a too large bite for me to take on. For most use cases the Clojure+ClojureScript REPL bundling that Calva did was enough and very easy to use. VS Code lets you work around the lack pretty well with its isolated windows and workspaces. But when Calva forced me to have four windows opened to manage a project with Clojure, ClojureScript, Babashka, Joyride, and Scittle, I had had enough. It turned out to be every bit as hard to solve as I thought it would be. I’ve been working with this almost every free hour for the last three months. First trying quite a few things that didn’t work, or that destroyed the previous “it’s very easy” story. Then figuring out how I could both keep the previous ease, yet make it very flexible for advanced use cases. From there it was all about write and rewrite and relentless testing over and over.
Also: Calva Backseat Driver has been updated in preperation for this since a while, and the AI Agents handle the multi-REPLs with ease.
Follow-ups in the thread and in #calva. Thanks to @devgiudev and @seancorfield for helping me with testing this so that I dare release it. 🙏 ❤️
Congrats on this rework! I know exactly how grueling this must have been to achieve. At some point I was interested in tackling this issue in Calva and spent some time investigating the at-the-time current implementation. I decided to tackle something else instead 😅 Nice work!
Haha, yes. I realize I made it sound like it is an inherently difficult thing to support. But really one of the hardest parts of it was the stateful spagetti that “managed” the sessions. 😃 Accidental complexity if there ever was one.
There’s still a lot of work to tame that beast, but at least it is much better now.
That demo video is awesome!
https://github.com/babashka/sci: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs
SCI is used in https://github.com/babashka/babashka, https://github.com/babashka/nbb, https://github.com/nextjournal/clerk, https://github.com/BetterThanTomorrow/joyride/ and many https://github.com/babashka/sci#projects-using-sci projects.
0.11.50 (2025-12-23)
• Add support for :refer-global and :require-global
• Add println-str
• Fix https://github.com/babashka/sci/issues/997: Var is mistaken for local when used under the same name in a let body
• Fix https://github.com/babashka/sci/issues/1001: JS interop with reserved js keyword fails (regression of https://github.com/babashka/sci/issues/987)
• sci.impl.Reflector was rewritten into Clojure
• Fix https://github.com/babashka/babashka/issues/1886: Return a map when dissociating a record basis field.
• Fix https://github.com/babashka/sci/issues/1011: reset ns metadata when evaluating ns form multiple times
• Fix for https://github.com/babashka/babashka/issues/1899
• Fix https://github.com/babashka/sci/issues/1010: add js-in in CLJS
• Add array-seq
https://github.com/babashka/scittle: execute Clojure(Script) directly from browser script tags via SCI! v0.7.30 (2025-12-23) • https://github.com/babashka/scittle/issues/114: Enable source maps (https://github.com/jeroenvandijk) • https://github.com/babashka/scittle/issues/140: Enable customizing the nrepl websocket port (https://github.com/PEZ) • Bump shadow-cljs and SCI
cc @pez
Christmas arrived early. Thanks! 🙏
isn't it the websocket hostname that is configurable now? the port# was already (?).
thanks for adding the Cons type fix for trove!
Introducing https://github.com/julienvincent/malt: Typed Clojure protocols using Malli schemas.
https://github.com/julienvincent/malt
[1.0.0-alpha.11]
Malt is a set of replacement macros for defprotocol, defrecord, reify, and extend-type which allow defining protocol interfaces that are typed using malli schemas and validated at runtime.
This pairing gives a lot of benefits and opens up a lot of future possibilities such as automatic implementation generation for networking protocols, [json-]schema generation, client generation etc.
It's currently in alpha, but I don't think the interfaces are going to change much going forward.
Hope you like it!
Very cool! Is there a chance this technique is applicable to multimethods?
It's most likely possible yes, but that won't be something I am interested in experimenting with. Controversial I am sure, but I think multi methods are terrible 😬
This is absolutely awesome!
Glad you like it! If you end up using it for anything please do tell me what you think
Oh I'm definitely using this for a whole bunch of projects of mine. I'll probably get a first real test run of it done later this week. The dev ergonomics of it are just so nice looking at the docs.
The timing on this is great for me, I was looking for something like this recently. I will certainly be trying this out soon.
I just implemented a part of an API for a project of mine with Malt, and it was just as easy as the docs make it look. Haven't run into any issues yet.
Hahaha cool! Keep me posted!
Introducing https://github.com/simm-is/distributed-scope - Write distributed code that looks like local code Variables from your scope automatically travel with your computation across peers. Built on https://github.com/replikativ/kabel for P2P networking. - Explicit variable capture with compile-time validation - Bidirectional hops between any connected peers - Both core.async and Missionary flavors - Works with https://github.com/replikativ/kabel-auth/ for authentication - Cross-platform: Clojure + ClojureScript Feedback welcome! Join the #simmis channel if you are interested.
How does security work in ClojureScript browser client, i.e. client can execute arbitrary queries and get any kind of data?
Hey @ahmed1hsn. The code is written in a cljc file and has to be deployed on both sides. So on the server you decide what logic the client can invoke, very much in the same way that you would with HTTP RPC endpoints. kabel-auth provides the ability to authenticate clients on the server as well, although this is WIP and I haven't deployed the current version of it myself yet (working on it).
it's very cool, is it correct to conceptualize this as a RPC framework? so basically async/await with abstracted transport
@dustingetz thanks! I like your visionary work on electric as you know. Yes, I have been thinking quite a bit about dispatch mechanisms and compilation, I would say async / await with inversion of control is in its "essence" about giving control to a remote dispatcher for some notion of remote. I would be interested to find more cateogory theory connections in terms of duality here (CPS <-> 'co'dispatch maybe?). This is why I also decided to distill this into https://github.com/simm-is/partial-cps, which makes a more minimal a la carte abstraction than other async framework options in Clojure (similarly to cloroutine). I can infer the free variables to send in distributed-scope automatically and make it a bit leaner, but I found making the intent of what is being transported explicit is actually helpful and more transparent. Electric as full compiler can do top-down analysis of the program and also know what is in the outer scopes and avoid having to send values through nested scopes, I have not worked on this yet. One thing I was aiming for is to be able to send datahike's db values over the wire back and forth and this works now, assuming you have store replica access on both ends. You can also do p2p streaming through kabel (replikativ does this for CRDT updates), or use nested distributed scopes to update atoms inside out in a streaming way, but my sense is that Electric does more to facilitate this and avoids RPC roundtrips more directly. I have put this under a maximally permissive license to make it easier to collaborate, I need to be able to freely hack and appropriate the pieces in my stack which became a limitation with Electric (besides my slightly different technical requirements). I am happy to discuss anything in more detail. And Happy Holidays 🎄 !
I'm curious - does this share lineage with Electric? This looks very cool. I should've read the readme closer lol
@jatkin thanks! It is inspired by it and other distributed continuation management approaches, it is not derived in any form from Electric's implementation.
Open source version of Rama eventually? ;-)
Hehe @borkdude, getting there... 🙂. Clojure is well suited for better distributed programming models, I think it is an underexplored area. Here is it integrated to provide Datahike cljs support: https://github.com/replikativ/datahike/blob/cljs-lean-cps/doc/distributed.md