clj-xref 0.1.0 — LLM-friendly cross-reference database for Clojure code https://github.com/danlentz/clj-xref Instead of feeding your entire source tree to an AI coding assistant, clj-xref lets it query the dependency neighborhood of the function it's working on — just the relevant code, in far fewer tokens. Built on clj-kondo static analysis, it generates a queryable xref database with *lein xref * or c`lj -T:xref generate`, then answers questions from the REPL: (xref/who-calls db 'myapp.orders/process-payment) (xref/calls-who db 'myapp.web/handler) (xref/who-implements db 'myapp.protocols/Billable) (xref/unused-vars db) (xref/call-graph db 'myapp.core/main {:depth 3}) Returns plain maps and vectors — compose with filter, map, group-by, or anything else. How much context does it save? Well, that is still an experiment, but Measured on clj-xref's own source:
┌────────────────────────────-┬────────────────────┬────────────────────┬───────────┐
│ Target │ Whole-tree │ Xref-guided │ Reduction │
├────────────────────────────┼────────────────────┼────────────────────┼───────────┤
│ core/index │ 8 files, 32K chars │ 1 file, 6K chars │ 80% │
├────────────────────────────┼────────────────────┼────────────────────┼───────────┤
│ analyze/transform-analysis │ 8 files, 32K chars │ 1 file, 7K chars │ 78% │
├────────────────────────────┼────────────────────┼────────────────────┼───────────┤
│ leiningen.xref/xref │ 8 files, 32K chars │ 3 files, 11K chars │ 66% │
├────────────────────────────┼────────────────────┼────────────────────┼───────────┤
│ analyze/classify-kind │ 8 files, 32K chars │ 1 file, 7K chars │ 78% │
└────────────────────────────┴────────────────────┴────────────────────┴───────────┘
Also useful for: dead code detection, codebase visualization (DOT/Graphviz output), impact analysis in CI, and
REPL-driven exploration of unfamiliar code.
Query API: who-calls, calls-who, who-references, who-macroexpands, who-implements, who-dispatches, unused-vars,
call-graph, apropos, ns-deps, ns-dependents. Inspired by SBCL's sb-introspect and Smalltalk's senders/implementors.
Built entirely on clj-kondo — please consider sponsoring @borkdude: https://github.com/sponsors/borkdudeWill give this a go. This might be useful when e.g. refactoring existing code (“who’s calling this function”)
clj-xref 0.1.1 — AI coding assistant integration is the headline. "robustness against clj-kondo edge cases" is the subtitle Check the readme for setup/AI assistant integration docs. Since 0.1.0: - New CLI: clj -M:xref who-calls ns/fn, unused, graph ns/fn, etc. - Claude Code /xref slash command (drop-in at .claude/commands/xref.md) - CLAUDE.md project guidance snippet — teaches Claude to reach for xref proactively before signature changes, deletions, or refactors instead of falling back to grep - Also: derived queries (unused-vars, call-graph, apropos), DOT/Graphviz output, incremental analysis (:only), and best-effort generation so clj-kondo errors no longer abort the build https://github.com/danlentz/clj-xref Detailed Info in Release notes: https://github.com/danlentz/clj-xref/releases/tag/0.1.1 I have some interesting ideas for next steps on this. Thanks everyone for having a look!
sorry this will happen soon its a good improvement. just trying to balance this with work
Say, if, in addition to xref/graph analysis the LLM were easily able to instrument a function to see inside its lexical scope? I always see Claude spinning up all of these mini sessions to debug / work out issues. Making that more efficient seems like it might save significant context
just spitballing, but there seem like good libraries for the scope capture bit
interesting idea!
and clj-kondo, while great, is ever only going to be an 80% solution. BUT...
The interesting hybrid
The real power would be combining tiers:
┌───────────────────────┬───────────────┬────────────────┬─────────┬──────────────────┬────────────────┐
│ Source │ Pre-expansion │ Post-expansion │ Runtime │ Source locations │ No eval needed │
├───────────────────────┼───────────────┼────────────────┼─────────┼──────────────────┼────────────────┤
│ clj-kondo (current) │ yes │ no │ no │ yes │ yes │
├───────────────────────┼───────────────┼────────────────┼─────────┼──────────────────┼────────────────┤
│ fdeps (Tier 1) │ no │ partial │ yes │ no │ no │
├───────────────────────┼───────────────┼────────────────┼─────────┼──────────────────┼────────────────┤
│ ASM bytecode (Tier 2) │ no │ yes │ no │ partial │ partial │
├───────────────────────┼───────────────┼────────────────┼─────────┼──────────────────┼────────────────┤
│ Java agent (Tier 3) │ no │ yes │ yes │ partial │ no │
├───────────────────────┼───────────────┼────────────────┼─────────┼──────────────────┼────────────────┤
│ Compiler AST (Tier 4) │ no │ yes │ no │ yes │ no │
└───────────────────────┴───────────────┴────────────────┴─────────┴──────────────────┴────────────────┘
so a lot to think about for next steps.
give it that, the more efficient (scope capture) debugging tools, then just teach it wisdom
not all tiers most likely. but more than kondo
something at least to fix macros
i'll push a 0.1.1-SNAPSHOT tonight that addresses those two GH issues and does a better "best effort" when kondo fails.
but then i think there are some cool directions to go with this
Ya absolutely
Thanks - 262k lines of code is a good stress test :).
have done so, thanks @dan.lentz!
That sounds like a reasonable fix
How long does the xref take on the 262k line project?
to generate, or to run a query?
Well, both
i'll check! 😄
Language files blank comment code
-------------------------------------------------------------------------------
Clojure 828 15418 3913 117983
ClojureScript 714 8042 2104 95075
ClojureC 510 6673 1698 50523
Markdown 3 59 0 132
JavaScript 2 4 0 34
-------------------------------------------------------------------------------
SUM: 2057 30196 7715 263747Wed Apr 15 14:21:48 CEST 2026
clj-xref: analyzing ["src" "test"]...
clj-xref: wrote 22057 vars, 254861 refs -> .clj-xref/xref.edn
Wed Apr 15 14:22:17 CEST 2026
around 30secs to generate!i can't do any queries at the mo, because of the bug
Not too bad. I'll try to get an 0.1.1 release out and take care of that
appreciated. if you want to push a commit i can use a sha dependency to do a quick test, just lmk!
Y ok will do. Let me circle back to it this afternoon
ok, 0.1.1 still WIP https://github.com/danlentz/clj-xref/pull/2
cheers, will try it and report back!
i added new experimental hooks for Claude / style commands eg /xref ns-deps ns that seems like a nice interface
tks @dcj !
Claude Code integration
clj-xref now ships an example /xrefhttps://github.com/danlentz/clj-xref/blob/0.1.1-refinements/doc/claude-slash-command.md for Claude. Copy it to .claude/commands/xref.md in your project to add cross-reference queries as Claude commands:
/xref init — generate/regenerate the xref database
/xref who-calls ns/fn — who calls this function?
/xref calls-who ns/fn — what does this function call?
/xref who-implements ns/Protocol — who implements this protocol?
/xref unused — find dead code (defined but never referenced)
/xref ns-deps ns — what namespaces does this one depend on?
/xref ns-dependents ns — what namespaces depend on this one?
/xref apropos pattern — search for vars matching a name pattern
/xref graph ns/fn — show transitive call graph
The slash command wraps the same CLI, so Claude runs the queries directly in your terminal. The included prompt guidance tells Claude to use xref proactively — checking callers before changing a signature, checking dependencies before refactoring, and regenerating after edits.
This works with any AI assistant that can run shell commands. The CLI is the interface; the slash command is just a convenience wrapper.does this need to reanalyze the entire project after a code change or does it have support for incremental analysis?
it does currently support a limited form of incremental (limited to changed files) but that was more of an experiment. I'm not sure its generally useful You would have to know your changes only had local impact
i tried to talk more about "what it is" vs "what it isn't" in the README
love the 'interact with/look at code like a graph' ideas, will have to give this a shot gratitude
@dan.lentz what drove you to build this, and would you like to get on a quick call? I see a lot of intersections between clj-ref and pando (http://clojure.getpando.ai)
So I asked Claude what they thought of this, and were eager to try. We created a skill to /xref init and then /xref {verb} for actual use.
Looking forward to trying this out in my next session!
Thanks for sharing @dan.lentz!!!
the one time claude didn't screw up. don't tell codex
that does sound useful
link?
https://gist.github.com/dcj/b0bb18a44b11eea3ebfab647c12c73a2
giving this a try! we have a large monorepo (263kloc), with a 60mb clj-xref edn db.
we use shadow-cljs with requires like
["@tanstack/react-pacer/debouncer" :as debouncer]
this causes this issue when using the query mode:
"Execution error at clj-xref.emit/read-edn (emit.clj:56).\nInvalid leading character: @\n"
i have a codex-generated assessment and suggested fix. would it be ok if i shared its full output with you via a GH issue, @dan.lentz?
We built something deeply inspired by Clojure's homoiconicity. pando is a tool for coding agents that treats code as data and has first class support for structural (i.e. using the AST) Clojure code navigation and editing. It works in addition to your existing tools - just connect over MCP. I'd love your feedback on it - https://clojure.getpando.ai Thank you kindly and looking forward to hearing from you! p.s. it's free for personal use and not OSS.
so, not open source?
Not yet at least :-)