Asko Nõmm

Invobi 1.0

I’m happy to say that after many iterations, I’m finally done and out with my invoicing service, Invobi.

Initially it was a web-based invoicing service, then web-based invoicing service that interfaced with AI’s through API’s so you could just describe your invoice, and while that worked reasonably well and I was just about to announce that as the version I was happy and done with, the amount of bot signups and other horribleness that the modern web has become made me reconsider.

At work I’ve been building MCP’s and with the fuck-ups of Microsoft and others ignored, I do see massive utility in today’s frontier model capabilities in using tools via MCP’s, and if done well, can totally see how it will shape the future of how we interact with technology, so I figured why not just make Invobi into an MCP as well.

There’s no web sign-ups, no database I have to maintain, no nothing. The only service I now run is the license/download service, but it has no database, and the downloads are proxied through my own Forgejo instance. In essense I just distribute a binary that is the MCP server and sell (offline) license keys to that MCP server. It’s just a one-time payment of $5 and the license key is valid for a year. Enjoy!


Ruuter 2.1

We’re rolling now! Just as I got ruuter 2.0 released with huge performance improvements I went ahead and added support for Jank as well. Ruuter is now a 4-runtime library: Clojure, ClojureScript, Babashka and Jank.

I’m very excited for Jank, even though it is the worst of 4 right now when it comes to performance, it should become the fastest, considering it runs on the LLVM.


Ruuter 2.0

Ruuter, my zero-dependency, runtime-agnostic Router for Clojure, ClojureScript and Babashka has a new release out. A pretty hefty one at that:

  • Best-match routing: Routes are now matched by specificity instead of first-match-wins. Literal segments beat parameters, parameters beat optionals, optionals beat wildcards. Route order in the vector no longer matters.
  • Segment trie: Routes are compiled into a trie (prefix tree) data structure for O(path-depth) matching instead of O(N) linear scan. This yields 4-380x performance improvements depending on route count and match type.
  • compile-routes function: New public function for explicit route compilation. Routes are also compiled implicitly and cached via memoization when using route directly.
  • Single wildcard constraint: Wildcard parameters (:name*) must now be the last segment in a path. Multiple wildcards per path are no longer supported.
  • No regex: Route matching no longer uses regular expressions. Matching is done via direct string comparison of path segments against a trie.
  • deps.edn only: Leiningen (project.clj) has been retired. All build, test, and benchmark tasks use deps.edn and bb.edn.

Massive performance improvements come with this release, which is something that’s been lacking a lot so far:

  • JVM (Clojure)
    • Small route sets: 1.6–4.1x faster
    • Medium route sets: 39–139x faster
    • Large route sets: 162–345x faster
    • Peak throughput: ~9.8M ops/sec (literal match)
  • ClojureScript (Node.js)
    • Small route sets: 0.9–6.5x faster (literal-first is within noise; params, wildcards, and misses see large gains)
    • Medium route sets: 14–40x faster
    • Large route sets: 38–167x faster
    • Peak throughput: ~1.3M ops/sec (literal match)
  • Babashka
    • Small route sets: 2.0–6.4x faster
    • Medium route sets: 11–32x faster
    • Large route sets: 32–182x faster
    • Peak throughput: ~1.1M ops/sec (miss/404 — fast trie rejection)

Why I’m not worried about AI job loss

All of this makes me suspect that, as long as we are in the cyborg era of human-AI complementarity, we should be quite optimistic about human labor. The world is governed by bottlenecks; as long as those bottlenecks are real, there will be complementarity between humans and AI; and if the human-AI combination can make human labor vastly more productive, we should expect that to be a very good thing: for consumers of course, who will benefit from an enormous consumer surplus, but also for workers.

Adapt or die, as they say.


Dompa 1.2.3

I’ve just released a new version of Dompa, a zero-dependency, runtime-agnostic HTML parser and builder.

  • You can now call defhtml functions inside other defhtml functions
  • You can now add doc strings to defhtml functions