Senior Principal Engineer at NewsCorp Australia: ClojureDart, AI, full-stack.
Two decades in software, and I have moved with the landscape: Java → Ruby → Clojure → ClojureScript → and most recently ClojureDart for mobile and desktop. Over the past year a tiny team and I have shipped a fleet of production ClojureDart apps for iOS, Android and macOS, alongside Clojure backends and ClojureScript SPAs that share a single mental model end to end.
My current interest is where functional programming meets AI-assisted development: building maintainable agentic workflows in Clojure, and sharing the patterns and pitfalls a small team learns by shipping at pace. When I'm not coding I'm writing experience reports for developers who appreciate the art of elegant, productive engineering.
🗣️ Speaking at Clojure/Conj 2026, and generally available to talk about ClojureDart, MCP/agent tooling, and using LLMs in real engineering workflows. Get in touch.
🔜 Clojure/Conj 2026 · Charlotte, NC
Production ClojureDart for iOS, Android, and macOS 📅 Friday, October 2 · 9:30–10:10 AM · Room W207CD
Over the past twelve months a tiny team has used ClojureDart (Clojure compiled to Dart, running on Flutter) to build more than a dozen production apps: a document scanner with on-device OpenCV, a transit tracker with realtime GTFS, a venture-capital deck triager with on-device LLM evaluation, a notes app with on-device sentence embeddings, a marketplace, an encyclopedia, a financial charting app, and more. This experience report distills the patterns that survived the trip from prototype to production: a single-atom-plus-
:watcharchitecture that replaces Riverpod and BLoC, a curated catalog of cljd-flutter pitfalls, and a reusable scaffold for new apps.
My second year on the Conj stage.
📺 Clojure/Conj 2025 · Charlotte, NC · Nov 2025
From Scripts to Buy-In: How Small Clojure Wins Create Big Opportunities
How small, high-impact Clojure automation (AWS workflows, replacing clunky Postman processes, automating Okta SSO) builds the credibility that earns you bigger Clojure opportunities at work.
▶ Watch the talk · 📝 My recap from Charlotte
| Talk | Venue | Date |
|---|---|---|
| Three native Clojures, one C game library Lightning talk to a room of typed-FP regulars (Haskell, OCaml, Rust), showing the same raylib examples running under three different Clojures: Jolt on Chez Scheme, jank via C++/LLVM, and JVM Clojure over Panama. bb run-all kept a real window cycling through the gallery in the background for the whole talk. The question that came up: why write it in Jolt when Chez Scheme is right there? Because Jolt reads like Clojure (vectors, lists, sets, maps), so there was no learning curve to cross first. |
FP-SYD Microsoft, North Sydney |
Aug 2026 |
| raylib, driven from Lisp Open-mic demo of raylib (a C game library) driven from Lisp, across all three suites: Jolt on Chez Scheme, jank via C++/LLVM, and JVM Clojure over Panama, plus the screen-capture and UI-automation tooling built to record their demo GIFs instead of testing by hand. All three suites are open source now; the capture tooling is still unreleased. |
02Ship Sydney Meetup Level 2, 63 Dixon St, Haymarket |
Aug 2026 |
| Three lenses, one mess: logic programming for the rest of us One RBAC authorization bug through three lenses, all in plain Clojure data: Prolog for role inheritance, Z3/SMT-LIB for conflicting constraints, a Mermaid-to-Prolog translation for reachability. Live REPL demo, closing on exposing solvers as LLM tools over MCP, where not hallucinating is the whole advantage. 📊 Slides |
FP-SYD Microsoft, North Sydney |
Jun 2026 |
| Supercharging Lisp with AI: Rapid Feedback Loops with Clojure and Claude Code Lightning talk to a room of 100+ builders. The demo ran on ClojureDart, Clojure compiled to Dart on Flutter, with a live REPL plugged straight into the running widget tree. That's the loop that lets Claude Code edit, hot-reload and assert against live UI in milliseconds instead of minutes. |
AI SYD Vercel × Relevance AI, Surry Hills |
Apr 2026 |
| The Anthropic Claude Ecosystem 66 slides end to end: ~/.claude as a personal AI config layer, Claude Code across CLI/IDE/desktop/CI, the agentic loop, MCP hosts and servers, and Agent Skills' three-level progressive disclosure. 📊 Slides · PDF |
Vibe Code Meetup Sydney |
Feb 2026 |
| Clojure for Java Developers: Building MCP Servers Without the Java Pain Cut a 350+ line Spring AI MCP server with 15+ annotations down to 180 lines with zero annotations, keeping full enterprise capability. |
Sydney JVM Community Canva HQ, Sydney |
Jul 2025 |
| Clojure for the Type-Loving Functional Programmer What Clojure offers a typed-FP audience, beyond the dynamic typing and the parens. |
FP-SYD | Jul 2025 |
| Java/Spring Boot Troubleshooting on Steroids with Clojure REPL Debugging Spring Boot from a Clojure REPL, set directly against traditional remote debugging in IntelliJ. Live coding on a sample app: debug, explore and modify at runtime with no restart and no redeploy. |
Sydney Java Meetup #22 Infomedia, Sydney |
Mar 2025 |
| Bridging Two Worlds: Leveraging Lisp-like Tools to Work with Python Scripting, extending and manipulating Python from Clojure with Basilisp and libpython-clj. |
SYDJANGO | Dec 2024 |
| Overview of Clojure for FP Live demos: libpython-clj via OpenCV, GraalVM via Babashka, AWS automation with the Cognitect AWS library, whisper.clj transcription, plus Rama and Jank. |
FP-SYD | Aug 2024 |
Clojure Corner: Interview with Burin Choomnuan · Flexiana, on Clojure, tooling, and building things in the open.
I co-host Gen AI Enthusiasts (AI Users), a 2,000+ member online generative-AI community running fortnightly sessions on prompt engineering, AI tooling and news, and practical LLM use.
I write at Clojure Civitas, where 11 articles so far are mostly browser-native ClojureScript with Scittle:
Plus b12n.net ("Lisp's Revenge"), my own blog, built with Clojure/Cryogen, where I keep browser-native slide decks: Mastering Claude Code · Diagrams as Text
ClojureDart in production. More than a dozen apps for iOS, Android and macOS in the past year: on-device OpenCV document scanning, realtime GTFS transit tracking, on-device LLM evaluation and sentence embeddings, charting, marketplaces. Most deployed internally, several bound for the app stores. That's the Conj 2026 talk.
Lisp against the C ABI. Three suites of raylib demos written in three different Clojures, each one reaching the same C game library the way its own host actually allows.
raylib-jlt: 119 examples in
Jolt, native Clojure on Chez Scheme. They call the
real libraylib directly over its C ABI through jolt.ffi: no wrapper library, no
codegen, no C shim. 42 shapes, 23 core, 16 in 3D, 10 games, 10 shaders, 9 generative,
5 text, 4 textures.
📖 Docs & full gallery
![]() bb tetris |
![]() bb space-invaders |
![]() bb boids |
![]() bb waving-cubes |
![]() bb point-cloud |
![]() bb rlgl-solar-system |
The interesting part is the ABI. raylib passes structs by value everywhere and Chez's
foreign-procedurecannot, so each struct gets the treatment its size actually earns:Colorrides in one register as a packed:uint,Camera2D/Camera3Dgo by pointer, andVector2/Vector3geometry is drawn through rlgl's scalar immediate mode.
b12n-raylib-jnk: 212 of the 217 official
raylib examples, ported to jank: Clojure compiled to a real native
binary through C++/LLVM. The shaders, textures, audio and text categories are complete.
📖 Docs & full gallery
![]() bb basic-pbr |
![]() bb magnifying-glass |
![]() bb cel-shading |
![]() bb shadowmap-rendering |
![]() bb spectrum-visualizer |
![]() bb animation-blending |
Here there is no FFI at all.
(:include "raylib.h")in thensform hands the real header to the C++ compiler, and raylib becomes ordinary interop:cpp/BeginDrawing,cpp/RAYWHITE,(cpp/Camera3D (cpp/Vector3 ...) ...). The by-value structs that cost Jolt a hand-written marshalling strategy are just constructor calls. No binding DSL, no generated shim.
b12n-raylib-clj: 113 examples in JVM Clojure, over coffi and JDK 22+'s Panama Foreign Function & Memory API. 37 core, 28 shapes, 25 models, 9 games, plus audio, text, textures and shaders. 📖 Docs & full gallery
![]() bb tetris |
![]() bb asteroids |
![]() bb background-scrolling |
![]() bb basic-lighting |
![]() bb solar-system |
![]() bb lorenz-attractor |
This is the one where the runtime does the marshalling for you. A binding is a single
defcfnnaming the C symbol and its types, and Panama builds the downcall from that description, so the by-valueColorthat Jolt hand-packs into a:uintis just a{:r 255 :g 0 :b 0 :a 255}map here, serialized from adefaliaslayout. The seam shows where raylib mutates through a pointer: those calls allocate in aconfined-arena, and the arena's lifetime is the one thing the abstraction will not hide from you.
Three hosts, one C library: Chez Scheme, C++/LLVM, and the JVM. Reading the same example three ways is the clearest map I know of where each runtime puts the boundary.
Desktop GUI, the Replicant way. glitter is a
GTK4 renderer for Jolt that follows
Replicant's model rather than React's: one
application-state atom, a pure state -> hiccup view function, top-down re-render on every
change, and event handlers that are data: [[:action/inc]], not closures. No
component-local state anywhere. 43 widget tags so far; the six demos below are two basics
plus four 7GUIs tasks.
📖 Docs & guide
![]() jolt counter |
![]() jolt todo |
![]() jolt crud |
![]() jolt flights |
![]() jolt temperature |
![]() jolt timer |
Immediate-mode GUI, the other shape. raygui-jlt
is glitter's opposite number: no retained widget tree at all, just
raygui, raylib's companion GUI library, called
straight over its C ABI through jolt.ffi, one shared bindings namespace under a suite of
small programs. raygui ships as a header only, so there is no library to install: the repo
vendors raygui.h and compiles its own. 24 examples across 7 groups (basics, inputs,
collections, containers, dialogs, color and styling), each with a committed screenshot.
📖 Docs & full gallery
![]() bb style-selector |
![]() bb color-picker |
![]() bb floating-window |
![]() bb sliders |
![]() bb list-view-ex |
bb icon-buttons |
The whole binding rides one signature: a bounding
Rectanglepassed by value, application state through a pointer, anintresult; 61 functions, nearly all shaped the same, no callbacks and no retained state to own. So the lifetimes almost vanish: a single module-level scratchRectangle, rewritten before each control, means no example allocates one inside a frame.GuiScrollPanelis the lone exception: two rectangles in one call, where Clojure's left-to-right evaluation would let the second clobber the first, so it gets a buffer of its own. Screenshots rather than GIFs here, deliberately: synthetic clicks do not actuate a raylib window at all, so a recording could never show a button being pressed.
The same suite, a different Clojure. raygui-jnk is raygui-jlt's twin in jank, which compiles Clojure through C++ and LLVM rather than Chez Scheme. Same 24 examples, same names, same descriptions, so the two ports read as one library seen through two implementations. What differs sits underneath: jank reaches raygui as C++ rather than over an FFI, and the binding ships as an installable package. raygui was not available to jank before this, which is why the sibling b12n-raylib-jnk substituted keyboard controls in seventeen of its examples. Those can be real controls now, on one dependency line, with no vendored copy and no build script of your own. 📖 Docs & full gallery
![]() bb tab-bar |
![]() bb color-picker-hsv |
![]() bb scroll-panel |
![]() bb gui-state |
![]() bb custom-input-box |
![]() bb spinner-value-box |
Jolt hands raygui a
Rectangleby value. jank cannot, because no native value crosses a jank function boundary at all, so the whole shape inverts. Every wrapper takesx y w has plain numbers and builds itsRectangleinside its own body, never accepting or returning one, and application state lives in boxed cells allocated before the frame loop. A closure counts as a boundary too, soloop/recurdoes work thatdoseqcannot. 53 of raygui's 61 functions are bound that way; most of the rest are font and icon-file calls the six vendored.rgsthemes make unnecessary, since each one carries its own embedded font. The six examples above are deliberately different ones from raygui-jlt's, so between the two sections all 7 groups show.
The same model, on native macOS. glitter-uikit
keeps glitter's model exactly as it is and swaps the toolkit underneath it: one
application-state atom, a pure state -> hiccup view, handlers as data, but every widget is a
real AppKit NSView rather than a GTK one. It began as a port of
glimmer-uikit, the AppKit renderer for glitter's
Reagent-style sibling, so both models sit in the same code and the contrast is easy to read.
19 widget tags so far, with the same :hbox/:vbox sugar, and
7GUIs tasks 1 through 6 all ship. That is one further
than glitter itself gets, so Circle Drawer had nothing to port from and its model is original here.
📖 Docs & guide
![]() bb counter |
![]() bb widgets |
![]() bb todo |
![]() bb crud |
![]() bb flights |
![]() bb timer |
The split earns its keep in the demos.
set-temperature,parse-dateandget-view-statecome over from glitter untouched, because they are pure Clojure with no toolkit anywhere in them, so only the view and-mainhad to change. Styling is where the two renderers stop agreeing. AppKit has no CSS classes and no inline style property, so:classand:styleare still accepted and diffed byglitter.core, then land here as honest no-ops. Circle Drawer asked for two things the renderer did not have yet.+[NSEvent mouseLocation]hands back aCGPointby value and no scalar message send can carry a struct, so the FFI layer grew struct-by-value sends.NSStackViewalso lays children out in order with no way to place one freely, so the:canvastag is anNSButtonwhose layer holds the circles. Those circles areCALayers rather than views, and a layer takes no part in hit-testing, which leaves a click free to reach the canvas under a circle and keeps hit-testing a pure function over the model.
And then teaching it. b12n-gamedev-course is what those 419 raylib examples were for: a free course that teaches Lisp and game programming as one thing, not "game dev, incidentally in Lisp." Six phases take you from never having written a line of Lisp to a capstone, and every lesson builds a real, playable game that teaches a Lisp idiom at the same time. Phase 3 is the one only those three raylib suites make possible: port a game you wrote across all three, and watch the boundary to C move under it. 📖 Read the course
![]() Lesson 1: Pong |
![]() Lesson 2: Breakout |
![]() Lesson 3: Snake |
![]() Lesson 4: Space Invaders |
![]() Lesson 5: Tetris |
![]() Lesson 6: Flappy Bird |
Those are the course's own games, running from its
exercises/code on its own vendored engine: the thing a student actually ends up with, not a borrowed screenshot. Lessons are CC BY-SA 4.0 and the code EPL-2.0, so teaching from it at a meetup or a classroom needs nothing from me. Phases 0 to 3 stand on the three raylib suites today; the later phases open up as the remaining sibling repos do.
Clojure meets AI. Agentic workflows, MCP servers, and LLM-driven developer tooling are where most of my time goes now. The first piece of that is out: mcp-tkx builds Model Context Protocol clients and servers in Clojure and ClojureScript, across five protocol revisions, and one session can serve both the handshake era and the newer stateless one at once. Plenty of the rest is still private, so those patterns tend to surface in talks and articles before the code does.
Public bits: mcp-tkx (MCP clients and servers, five protocol revisions) · b12n-gamedev-course · raylib-jlt · b12n-raylib-jnk · b12n-raylib-clj · glitter (Replicant-style GTK4 for Jolt) · glitter-gl (OpenGL geometry and shaders for it) · glitter-uikit (the same model, on native macOS AppKit) · raygui-jlt (immediate-mode GUI for Jolt) · raygui-jnk (the same suite, for jank) · dartclojure.el (Dart/Flutter → ClojureDart, in Emacs) · viip · Clojars · RubyGems
I started jlt-commons in August 2026, a community-led home for Jolt libraries and tooling. Jolt is young, so most of its ecosystem is still one person's side project, and a side project stops the month its author gets busy. The org gives that work somewhere to land, and gives anyone who wants to help a place to do it that is not someone else's personal account.
There are two ways in. Adoption is for a project whose maintainer can no longer look after it. We ask the current owner first, every time, and prefer a transfer over a fork so the stars and the issue history come along. Incubation is for new work, whether that is a port of a Clojure library people already rely on or something the core team would rather not own. The bar is a real gap and someone willing to maintain it, which is deliberately low while the language is this young.
It is not an official Jolt project. The language and the libraries its core team maintains live in jolt-lang.
What is there so far:
- raylib-jlt, the 119 raylib examples above, and the first thing I moved across from my own account. Its docs moved with it, off my own hosting and onto the org's.
- raygui-jlt, the immediate-mode GUI suite, transferred the same day and onto the same docs setup.
- glitter, the GTK4 renderer above, with glitter-gl for OpenGL geometry and shaders and glitter-uikit for the same model on native macOS AppKit. All three went across together and publish at jlt-commons.github.io.
- docs-engine, the generator behind every project's documentation. A project writes markdown and a short config file, and gets syntax highlighting, mermaid diagrams and a theme that follows the reader's light or dark setting, without maintaining any of that itself.
- meta, the governance and the proposal queue, kept short enough that people will actually read it.
If you maintain something in Jolt and would rather it outlived your own free time, or you want to build something and would rather not do it alone, the proposal queue is open.
b12n-oss is where my own open source lands. It is a
different thing from jlt-commons above, which is community-led and specific to Jolt. This
one is just mine, and the name is a numeronym for burinchoomnuan: the first letter, the
twelve in between, then the last, the same trick as i18n and k8s.
- mcp-tkx, a Clojure and ClojureScript library
for building Model Context Protocol clients and servers. Five protocol revisions from
2024-11-05through2026-07-28, and a single session can serve both the handshake era and the stateless one, so a server does not have to pick a side while its clients catch up. The newest revision drops the handshake entirely and replaces server-initiated requests with multi round-trip results, which is a real shift if you already run a server. It is a fork of Metosin's mcp-toolkit, with the namespaces deliberately unchanged so it stays a drop-in. Runs on the JVM, on Node, and on Babashka. Docs, EPL-2.0. - docs-engine, a fork of the jlt-commons generator, so projects in this org publish through the same setup rather than a second one built from scratch.
Most recent is jolt-lang/jolt
itself, with 15 commits across July and August 2026 to the Clojure-on-Chez-Scheme host: :string
carrying NULL in both directions through the FFI, fiber-parking for subprocess pipe I/O, and
a cross-compilation path (tarm64osx → ta6osx via Chez xpatch, macOS → Linux via zig cc)
with a CI cross-smoke workflow behind it. It is the runtime under
raylib-jlt,
raygui-jlt, glitter
and glitter-uikit, so the patches tend to fall out of
building on it.
Longer-running: contributions to babashka/process, bhauman/clojure-mcp, zero-one-group/geni, BrunoBonacci/graalvm-clojure, yogthos/Selmer, clojure-emacs/clomacs, dundalek/closh, juxt/mach, apache/incubator-mxnet, and others.
📌 Two handles, one person. @agilecreativity is my original account, from before I found Clojure, and a lot of my older OSS commits live there. @burinc is where I work now.
| 🌐 Blog | b12n.net |
| in/burinc | |
| 🐦 X | @agilecreativity |
| ✍️ Articles | Clojure Civitas |
| 🐙 GitHub | @burinc · @agilecreativity |
Lisp · Clojure · ClojureDart · Emacs · and a stubborn belief that small tools compound.














































