Fork me on GitHub

@filipematossilva updated his npm package to fall back on the jar if the native version isn't supported.


This means that when you install the NPM package on Windows and install the clojure-lint plugin in VSCode, linting should work on save now

Filipe Silva10:10:31

you should be able to do it globally even, via npx clj-kondo --lint src/


using a JVM, so feedback might not be as fast with the native version, but it should work I guess!

Filipe Silva10:10:40

(if you don't want a local package)

Filipe Silva11:10:11

was just testing if the extension just worked if I installed the package globally

Filipe Silva11:10:26

I'm on windows and did npm i -g clj-kondo

Filipe Silva11:10:41

the binary works

Filipe Silva11:10:43

$ clj-kondo
clj-kondo v2019.10.11-alpha

Usage: [ --help ] [ --version ] [ --lint <files> ] [ --lang (clj|cljs) ] [ --cache [ true | false ] ] [ --cache-dir <dir> ] [ --config <config> ]


  --lint: a file can either be a normal file, directory or classpath. In the
    case of a directory or classpath, only .clj, .cljs and .cljc will be
    processed. Use - as filename for reading from stdin.

  --lang: if lang cannot be derived from the file extension this option will be

  --cache-dir: when this option is provided, the cache will be resolved to this
    directory. If --cache is false, this option will be ignored.

  --cache: if false, won't use cache. Otherwise, will try to resolve cache
  using `--cache-dir`. If `--cache-dir` is not set, cache is resolved using the
  nearest `.clj-kondo` directory in the current and parent directories.

  --config: config may be a file or an EDN expression. See

Filipe Silva11:10:58

but the extension says

Filipe Silva11:10:00

Clojure Lint extension loaded.
Please report any issues to 
clj-kondo was not found on the path. Please install it following the instructions
located here: "

Marc O'Morain11:10:01

@filipematossilva did you re-open VSCode after putting clj-kondo on the %PATH%?

Marc O'Morain11:10:29

what do you see when you run clj-kondo from a CMD.EXE terminal?

Filipe Silva11:10:58

yes, I restarted vscode, just tried restarting again

Filipe Silva11:10:07

on cmd I see this

Filipe Silva11:10:10

Microsoft Windows [Version 10.0.18362.418]
(c) 2019 Microsoft Corporation. All rights reserved.

clj-kondo v2019.10.11-alpha

Usage: [ --help ] [ --version ] [ --lint <files> ] [ --lang (clj|cljs) ] [ --cache [ true | false ] ] [ --cache-dir <dir> ] [ --config <config> ]


  --lint: a file can either be a normal file, directory or classpath. In the
    case of a directory or classpath, only .clj, .cljs and .cljc will be
    processed. Use - as filename for reading from stdin.

  --lang: if lang cannot be derived from the file extension this option will be

  --cache-dir: when this option is provided, the cache will be resolved to this
    directory. If --cache is false, this option will be ignored.

  --cache: if false, won't use cache. Otherwise, will try to resolve cache
  using `--cache-dir`. If `--cache-dir` is not set, cache is resolved using the
  nearest `.clj-kondo` directory in the current and parent directories.

  --config: config may be a file or an EDN expression. See


Filipe Silva11:10:07

I suspect this is due to npm creating both clj-kondo and clj-kondo.cmd

Filipe Silva11:10:22

cmd.exe will actually use the latter (I think?)

Filipe Silva11:10:49

C:\Users\kamik>where clj-kondo
C:\Program Files\nodejs\clj-kondo
C:\Program Files\nodejs\clj-kondo.cmd

Marc O'Morain11:10:52

@filipematossilva can you rename clj-kondo to clj-kondo.exe please and see if that affects the issue?

Marc O'Morain11:10:00

That might be the issue.

Marc O'Morain11:10:17

Windows process launching is “interesting”

Filipe Silva11:10:46

I can't do that, because just renaming it doesn't make it a real exe

Filipe Silva11:10:48

This version of C:\Program Files\nodejs\clj-kondo.exe is not compatible with the version of Windows you're running. Check your computer's system information and then contact the software publisher.

Marc O'Morain11:10:54

oh, what file type is it?

Filipe Silva11:10:37

it's a .cmd script


maybe making the script command configurable works?

Marc O'Morain11:10:43

That’s going to be the issue. I’m calling execFile which is not using a shell, it’s trying to execute a binary directly I think.

Filipe Silva11:10:57

that part is out of my hands though, it's how npm/yarn do things

Filipe Silva11:10:16

it'll create those binaries automatically

Marc O'Morain11:10:48

This should be straightforward to fix in clojure-lint. But I don’t know how 😄

Marc O'Morain11:10:08

I’m on a mac right now, I might boot Windows later today or tomorrow and have a look at it.

Marc O'Morain11:10:21

PRs are always welcome thought!


Different issue: to make linting on Windows speedier this could also work:

Filipe Silva11:10:49

@borkdude I imagine that'd require some extra process communication that doesn't yet exist, right?

Filipe Silva11:10:52

@marc-omorain I think it's enough to also try running clj-kondo.cmd instead of clj-kondo on windows... is there an easy way for me to test that? e.g. whats the global extension dir, I can try changing it there


the way I imagine it is you run java -jar clj-kondo.jar --server 1337 once in your project dir (so one server per project). This startup could be automated by checking if it already runs and if not start it. and then there will be a clj-kondo-client which will support exactly the same command line args as clj-kondo, but acts as a proxy between the editor and the jvm process


maybe the client can just be named clj-kondo which will start the server in the background if it's not already running, to make things more align with the binary


preferably that client will be very very fast and supported on all platforms, so maybe Go is a good choice there


hey, this looks a lot like what @dave is doing with Alda 🙂

👍 4

Yep, that sounds almost exactly what I'm doing! Actually, Alda v1 (the current major release version) has a client written in Java. Alda v2 has a Go client, but I'm also doing something different there where I'm moving most of the logic into the client.


I might look at your go client code and how you distribute it. Never done any Go


When you write the client in a JVM language, one benefit is that you can package it into the same uberjar as the server, and just have a single executable that can run in either client or server mode. That simplifies releases


yeah, but I'm trying to workaround JVM startup time


it's just that GraalVM doesn't work that well yet on Windows


so a thin Go client + JVM server process might work


I was thinking the Go client can start the JVM server process when it wasn't started yet


something for the hammock


That sounds like a promising approach!

Filipe Silva11:10:54

@marc-omorain yeap, using clj-kondo.cmd in the extension on windows works!


as part of that PR you could maybe also check if clj-kondo was installed via npm or have a fallback, if clj-kondo does not exist, then try clj-kondo.cmd? @filipematossilva

Filipe Silva12:10:07

to do that in a cross platform way would require a somewhat more involved approach

Filipe Silva12:10:15

just trying to run the commands isn't a great approach, because that can take a while

Filipe Silva12:10:48

so it would be an overhead that might not be reasonable depending on how even these are ran

Filipe Silva12:10:58

something like shelljs could be used to provide a cross platform which command, and then we could do which clj-kondo

Filipe Silva12:10:08

which on windows will return the .cmd (in the npm case)

Filipe Silva12:10:37

and whatever else is actually ran by the system in the non-npm case


I wasn't suggesting running them, just checking if they exist on the path?


not sure what you can and cannot do in visual studio code out of the box without installing extra stuff

Filipe Silva12:10:33

hmmm I'm not that familiar with the vscode builtins myself...

Filipe Silva12:10:00

which in shelljs would check the path as you describe, but checking it without shelljs would need some finicky cross platform coding


but that might not work for the PATH path

Filipe Silva12:10:49

no, it doesn't

Filipe Silva12:10:00

that's just checking if a particular absolute path exists

Filipe Silva12:10:24

but it might be anywhere in the path really


I don't know how shelljs performs under Windows. The check has to be fast


can't see anything here why it would be slow: (just skimmed it)


if we're going to do something more sophisticated, maybe it's good to populate the command variable outside the lint function, only at startup?


I'll leave that to you @marc-omorain and @filipematossilva to decide 🙂

Marc O'Morain12:10:57

I’m working on a patch for shelljs now


Shouldn't the extension just bundle the npm package?


@marc-omorain this which command is now executes every time you lint a file. I don't know if this is milliseconds, then it probably doesn't matter, but maybe it makes sense to lift it outside the lint function.

Marc O'Morain12:10:51

Yeah, I’ve been thinking about that. Users would have to restart VSCode after installing clj-kondo in that case.

Marc O'Morain12:10:02

But that’s probably going to be the case on Windows anyway?


not sure, yeah, tradeoff

Marc O'Morain12:10:44

I could cache the positive result though.


Right. I think optimizing for speed for most common usage is maybe a sane thing to do

Filipe Silva12:10:17

sorry for the delay, was AFK for a while

Filipe Silva12:10:34

yeah I don't know how long which takes, but it might take a while depending on your path

Filipe Silva12:10:45

and it's really just something that needs to happen once

Filipe Silva12:10:01

so it makes sense to lift it out

Filipe Silva12:10:17

I think it makes sense to bundle clj-kondo as a npm dep as well, but that makes it a bit heavier and since there's no override, locks the user to a certain version

Filipe Silva12:10:03

other npm based extensions like tslint and the like usually do a priority list with override > local > bundle


yeah, I would prefer letting users decide how to install it


and if it's not installed then use the included package


if that's possible (so what Filipe said)


Maybe implementing some diagnostics in the LSP works for most editors as well.


So you can start kondo as an LSP server and then lint using existing LSP tools?

💡 4
Filipe Silva14:10:23

I imagine @pez has a LSP server on Calva, since it offer completion


No LSP yet. Calva's completion is nrepl based.


I want to experiment with starting a clj-kondo daemon on the repl server. And provide an API for the linter extension.

Marc O'Morain14:10:20

Some error messages examples ^

Filipe Silva14:10:50

elm really went the extra mile with error messages


@pez That's kinda the same as so maybe we can collaborate. But maybe if this server mode supports LSP it makes it easier for existing tooling to use as well


well maybe it's not the same. if you have nREPL you have a running JVM so that's the mechanism to avoid startup


so there isn't anything extra needed for that


Yes, that's the idea.


interesting. I'll let this sit on the hammock some more and see how your approach works out


Read that issue now. As for a node version. Could clj-kondo be made a cljc project?


I think it could, but this would mean me taking a sabbatical of one - three months, maybe a Clojurists Together sponsorship. Not sure when I'll be able to do that amount of work


Our next funding round is coming up very soon, we'd love to have you apply!


Me too. I'm sure I will one day, but not this time 🙂


> We don't have an exact date for when this is going to be ready, but it is coming soon. For members interested in learning more, please reach out and we're happy to give you a preview. I'm interested 😉


Most work is porting the rewrite-clj parser bits to CLJS (which is already done in @lee's port of rewrite-clj, but we can't use that off the shelf since there are changes from the original for good reasons).


Long term it's something I'm open to, but not something that will be there soon, unless someone else is willing to do this.


It would be cool to be able to invoke clj-kondo in a browser playground all client side


Before I send this out to the tweetosphere, can you confirm if this works now @filipematossilva and @marc-omorain? 🙂

Clj-kondo @ NPM (by @filipematossilv) now falls back to .jar file if native isn't there. If you use Windows:

- npm install -g clj-kondo
- in VSCode: install clojure-lint (by @atmarc) 
- edit Clojure file, hit save and enjoy feedback!

Report findings at:


(Still not sure if running a JVM on save feels that great, maybe it should be configured as a command, or that's already possible?)


Is there a reason why the Clojure lint extension does not include the clj-kondo npm module?

Filipe Silva19:10:17

I think it should work after Marc does a release

Filipe Silva19:10:31

but earlier today there was no release I could test

Filipe Silva19:10:31

to be fair the npm distro of clj-kondo exists as of a couple of days, this is all very new


@borkdude: I’ve started to think there is not all that much to gain from starting clj-kondo through nREPL, if you implement that server mode. Then an extension like Clojure lint can bundle the npm package, run clj-kondo in server mode and hand it linting tasks. The only difference would be a JVM process less, but that is not too much of a bother, is it?

Filipe Silva19:10:43

version control is a concern, if you always use the bundled version you can't control it (hence the local bit)

Filipe Silva19:10:18

(this is unrelated to server concerns/benefits)


I agree with Filipe: there should always be a way for users to override the bundled one with their own package manager


@filipematossilva, not sure what is meant with no overrides, but if I understand it… nothing stops Clojure lint from offering the user to specify if the bundled version should be used or something else.

Filipe Silva19:10:21

yes there's nothing stopping it, it's just functionality that would need to be developed


yeah, but we are develpers, after all. 😃


@pez I'm investigating LSP mode. That could work for all kinds of editor plugins. But it might take a while before I have this, while including it in nREPL might be more or less trivial (don't know)


LSP mode would be cool.

Filipe Silva19:10:57

A good example is typescript: you don't always want the latest version, and you don't want to manually config each project you open. VSCode automatically picks up your local version if you have it, but also lets you specify a version on disk to use (e.g. a global you want). But it also bundles its own version that it uses for many things, like auto-fixes and code-intel for JS.


Yeah, that’s nice. Clojure lint could do the same.


I have an lsp branch and it does this right now:

$ lein clj-kondo --server
Exception in thread "main" java.lang.ClassCastException: org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor$1 cannot be cast to java.lang.Number, compiling:(/private/var/folders/2m/h3cvrr1x4296p315vbk7m32c0000gp/T/form-init8209597301223963447.clj:1:125)
Just hacked on it for half an hour 😉

Filipe Silva19:10:55

btw @pez @borkdude, have you looked into suggested fixes?

Filipe Silva19:10:08

that's something really nice in VSCode

Filipe Silva19:10:31

it's mostly code transforms

Filipe Silva19:10:57

some of them come from the tslint I believe, and some come from VSCode TS support

Filipe Silva19:10:32

it's stuff like import organizing, correction for common mistakes, and auto-imports

Filipe Silva19:10:40

the latter is ostensibly the most useful imho

Filipe Silva19:10:19

you start writing a var name that doesn't exist in the current module, you get a red squiggly that tells you the ref is bad

Filipe Silva19:10:34

but it also tells you something like "Did you mean to import X?"

Filipe Silva19:10:41

then it does it for you

Filipe Silva19:10:52

I think it's LSP powered but am not sure


It’s probably LSP powered.


@filipematossilva Implementing fixes is not in scope for clj-kondo, there are just too many things to do already 🙂


Hmm, there is which does a lot of refactorings. Maybe it could adopt clj-kondo as a library, since it also mentions joker


That might work well, since clojure-lsp already does transformations and it can just pick up on the information the clj-kondo provides


That would also be a solution in Windows


and it would save clj-kondo figuring out all the lsp stuff


@dave I see you're a committer there. ^

Filipe Silva19:10:56

@snoe seems to be on slack

Filipe Silva19:10:22

(@snoe is the owner of clojure-lsp, we were talking about clj-kondo LSP support)

Filipe Silva19:10:17

btw I see there's a VSCode POC on, was it ever released as an extension?


hiya! it wasn't released, I would like someone who uses vscode to take it over.

Filipe Silva20:10:37

Hmmm I use VSCode almost exclusively. How can I help?

Filipe Silva20:10:13

although to be fair this sounds very complimentary to @pez’s vscode Calva extension

Filipe Silva20:10:24

maybe it could be incorporate somehow? or maybe made optional


We have been experimenting a little with it and we love it. However, we haven’t had the time to ponder if we should incorporate it. Maybe we should, and maybe we should even take it over… But that is something I need to think quite a bit about before deciding. We might be spreading ourselves thin if we do that.


@filipematossilva I'm not sure, I would like it so vscode users can be sure they have the latest clojure-lsp release. If that can be done as a separate repo that downloads from github releases that would be nice.. If it's most usable inside the repo that's fine and I can take prs and work to getting the maintainer commit access.

Filipe Silva20:10:16

@snoe I just did that for clj-kondo, by distributing the binaries via npm

Filipe Silva20:10:45

it downloads binaries according to platform, clj-kondo distributes native binaries for linux and osx, and a jar for windows

Filipe Silva20:10:42

would it help if I did something similar for clojure-lsp?

Filipe Silva20:10:07

from the releases page it's not clear to me what platform the binary is for, I guess linux/osx?


it's wrapping a jre - there's some difficulties with windows but yeah, whatever works would be great


sorry wrapping a call to a jre


@snoe I notice both our projects (clojure-lsp and clj-kondo) are maintaining their own fork of rewrite-clj now 🙂


I'm considering LSP support for clj-kondo for people who can't run the binary (most specifically Windows users)


But since you're basically already doing LSP for Clojure, maybe it could be interesting to see if including clj-kondo as a linting library in clojure-lsp works well


Just an idea, since you already mentioned joker in your README


I would love to do this. My difficulty is really how to avoid parsing files once for lsp and once for kondo. Maybe I shouldn't worry about it cause the kondo linting would be very nice for lsp users.


Or you could ride along on the vendorized version of rewrite-clj in clj-kondo


If you would include joker then the files would also be parsed twice btw


Right joker is file specific though, I think kondo crawls the project?


not really, it just lints whatever you tell it to


I'm not sure what the workflow is with LSP. Is a server started per project, file or editor instance?


clj-kondo kinda assumes that your working dir is the project directory


It depends on the client, but clojure-lsp assumes one is started per project.


the benefit of linting your entire project/classpath is that it learns about the arities of functions in all namespaces, so you will have extra warnings, but it's completely optional


oh that's in line with how clj-kondo works then, nice


typically users put a .clj-kondo directory in the root of their project. then clj-kondo will save information to the .clj-kondo/.cache directory every time you lint a file (= typically when you edit a file)


that's how it remembers arities/etc. of previously edited namespaces


scratch the idea of using the vendored clj-kondo parser btw, that's a bad idea and you won't be able to actually generate the original output again