Asi jank
jank-lang: native Clojure on LLVM with seamless C++ interop. Use when writing native Clojure, bridging C/C++ libraries, or applying SICP Ch4-5 metalinguistic abstraction concretely.
git clone https://github.com/plurigrid/asi
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jank" ~/.claude/skills/plurigrid-asi-jank-82df75 && rm -rf "$T"
skills/jank/SKILL.mdjank
Write Clojure for humans, compile to LLVM IR for machines.
Native Clojure on LLVM. Seamless C++ interop. 3,117 stars. Alpha January 2026. Jeaye Wilkerson.
Use: native perf, C/C++ libs, AOT binaries, SICP Ch4-5 concretely. Don't use: pure JVM (
clojure), scripting (babashka), browser (shadow-cljs).
Theoretical Foundations
| Source | Concept | jank |
|---|---|---|
| SICP 1 | λ, higher-order fns | fns → LLVM IR; closures = GC'd C++ objects |
| SICP 2 | Abstraction barriers | Persistent data in C++; = barriers |
| SICP 3 | State, concurrency | (#674); atom/ref/agent; thread-safe |
| SICP 4 | Metacircular eval | jank IS it — Clojure evaluating Clojure → native |
| SICP 5 | Register machines, GC | LLVM IR = registers; Boehm GC = 5.3; AOT = 5.5 |
| SDF 1-2 | Combinators, DSLs | ,, compose; = sub-DSL |
| SDF 3-4 | Generic ops, matching | traits + Clang overload resolution |
| SDF 7 | Propagators | Bidirectional: jank string ↔ |
| SDF 8 | Degeneracy | REPL → JIT → AOT = multiple paths, same result |
Compile AND interpret simultaneously. C++ interop = escape hatch into the machine.
Pipeline
Statically typed. Zero overhead. No reflection. Four stages per interop call:
- Wrapper — C++ helper (unpack args, box return)
— trait-resolved type conversion at compile timeconvert<T>- Pointer adj —
, const/ref for membersthis - IR — CppInterOp → LLVM IR → linked
Bootstrap: Phase 1 builds compiler (C++/LLVM), Phase 2 compiles jank's stdlib with itself.
Interop
:: → . (std::string → std.string). Clojure resolves first; cpp/ disambiguates.
;;; HEADERS — cpp/raw: global scope, returns nil, workaround escape hatch (cpp/raw "#include <cstdlib>") (cpp/raw "struct vec2 { float x{}, y{}; }; vec2 operator+(vec2 const &l, vec2 const &r) { return { l.x + r.x, l.y + r.y }; }") ;; -I <path> -D FOO -L <path> -l <lib> ;; :jank {:include-dirs [...] :library-dirs [...] :linked-libraries [...]} ;;; FUNCTIONS — overloads, implicit conv, void→nil, variadics, templates (printf "result: %d\n" (rand)) (let [u (getenv #cpp "USER")] (println u)) ; #cpp = unboxed C++ value ;;; MEMBERS — .foo call, .-foo field (public, const/ref-qual aware) (let [s (cpp/cast std.string "meow")] (.size s) (.substr s 1 3)) (.-npos std.string) ;;; OPERATORS — 45: + - * / % == != < > <= >= && || ! & | ^ ~ << >> = += [] * -> ++ -- (let [ab (cpp/+ (vec2. #cpp 1.0 #cpp 2.0) (vec2. #cpp 4.0 #cpp 3.0))] (println (.-x ab) (.-y ab))) ;;; TYPES #cpp 42 #cpp 3.14 #cpp "hello" ; unboxed int, double, char[] cpp/true cpp/false cpp/nullptr ; native C++ bool/null (cpp/value "std::numeric_limits<int>::max()") ; complex exprs (cpp/type "std::map<std::string, int (*)(int)>"); templates cpp/int** ; pointer types ;; enums (scoped+unscoped), function ptrs, functors/lambdas all work ;;; CAST (cpp/cast cpp/int (rand)) ; static_cast + convert<T> (cpp/unsafe-cast (cpp/type "unsigned char*") s) ; reinterpret_cast ;;; MEMORY — bdwgc GC; cpp/delete eager for RAII (let [p (cpp/new cpp/int (cpp/int. 500))] (assert (= 500 (cpp/* p))) (cpp/delete p)) ;;; ARRAY + BOX (cpp/aget arr idx) (let [b (cpp/box (cpp/new my_db.conn #cpp "localhost:5758"))] (.query (cpp/unbox my_db.conn* b) "SELECT 1")) ; compile-time type check ;;; CONVERT TRAIT — custom: specialize jank::runtime::convert<T> ;; template <> struct jank::runtime::convert<MyType> { ;; static MyType from(object_ptr o) { ... } ;; static object_ptr to(MyType const &v) { ... } };
Examples
;; JSON pretty-printer (header-only nlohmann/json) (cpp/raw "#include <fstream>") (cpp/raw "#include \"json.hpp\"") (defn -main [& args] (let [f (std.ifstream. (cpp/cast std.string (first args)))] (println (.dump (nlohmann.json.parse f) 2)))) ;; zlib compression (-l z) (cpp/raw "#include <zlib.h>") (defn compress-str [input] (let [src (cpp/cast (cpp/type "const Bytef*") input) n (cpp/cast cpp/uLong (count input)) dn (compressBound n) dst (cpp/new (cpp/type "Bytef") dn)] (compress dst (cpp/& dn) src n) (cpp/box dst))) ;; FTXUI hiccup → C++ flexbox (render-hiccup [:vbox [:hbox [:text "NW"] [:filler] [:text "NE"]] [:filler] [:hbox [:filler] [:text "center"] [:filler]] [:filler] [:hbox [:text "SW"] [:filler] [:text "SE"]]])
Usage
jank repl # eval/apply jank run app.jank # JIT jank -I vendor -l z run app.jank -- args # + native libs jank compile app.jank -o app # AOT binary lein new org.jank-lang/jank proj && lein run # Leiningen lein compile # AOT → ./a.out zerobrew install jank-lang/jank/jank # install macOS (also: apt, yay, nix)
Status (Jan 2026)
| Done | Missing |
|---|---|
| Interop: headers, fns, members, ctors, cast, box, 45 ops | Records, Protocols |
, , , , enums, lambdas | Types in jank syntax |
| PCH, AOT, two-phase, deferred compilation (+50%) | CIDER (Clang bug) |
, thread safety, regex, UUID, instant, BigDecimal | Library parity: 57% |
| nREPL + imgui (Kyle Cesare); zerobrew/apt/AUR/nix | Syntax parity: 93% |
Contributors: Jeaye Wilkerson + Saket (interop), Monty (compiler/distro), Jianling (catch/stdlib), Shantanu (REPL/tests/bigint), Kyle Cesare (nREPL/imgui), djblue, pfeodrippe, E-A-Griffin, Samy-33, cjbarre.
Δ Clojure
| Clojure | jank |
|---|---|
| Classpath | Module path |
→ array-map | Always hash-map |
fn | special form |
Nested | No (like CLJS) |
| |
/ | Not yet |
→ exception | UB |
| |
Ecosystem
scripts/splitmix64.jank — SplitMix64 → hue → Girard polarity → TAP. jank run scripts/splitmix64.jank -- 42
scripts/neanderthal.jank — ersatz Neanderthal (uncomplicate) syntax on Eigen via jank interop. BLAS L1/2/3: dv, dge, dot, axpy, scal, mv, mm. MPC primitives (mpc-predict, mpc-cost, mpc-horizon). Append-only log for promise chain resolution. jank -I /path/to/eigen3 run scripts/neanderthal.jank
asi/ies/music-topos/lib/crdt_sexp_ewig.jank — same PRNG + CRDT ops + Lager actions.
jank_interop.duckdb — commits(is_interop), pull_requests, repo_meta.
Connections
| Skill | Trit | |
|---|---|---|
| 0 | Language family |
| 0 | Ch4-5 realized |
| 0 | Scripts ↔ native |
| +1 | Complementary native |
| 0 | SDF 7 bidirectional |
| 0 | SplitMix64 shared |
clojure(0) + jank(+1) + property-based-testing(-1) = 0 mod 3
Cat#
+1 PLUS | Prof | y (Yoneda) | Lan | #E847C0 — compilation ⊣ interpretation, mediated by REPL.
Refs
jank-lang.org | book | GitHub | interop blog 1 2 3 | SICP | SDF