Show HN: Kumi – a portable, declarative, functional core for business logic

kumi-play-web.fly.dev

4 points by goldenCeasar 16 hours ago

Hi HN, I'm the author of Kumi, a declarative, statically-typed, array-oriented, compiled DSL for building calculation systems (think spreadsheets). It is implemented entirely in Ruby (3.1+) and statically checks everything, targets an array-first IR, and compiles down to Ruby/JS. I have been working on it for the past few months and I am curious what you think.

The linked demo covers finance scenarios, tax calculators, Conway's Game of Life (array ops), and a quick Monte Carlo walkthrough so you can see the zero-runtime codegen in practice. (The GOL rendering lives in the supporting React app; Kumi handles the grid math.)

The Original Problem:

The original idea for Kumi came from a complex IAM problem I faced at a previous job. Provisioning a single employee meant applying dozens of interdependent rules (based on role, location, etc.) for every target system. The problem was deeper: even the data abstractions were rule-based. For instance, 'roles' for one system might just be a specific interpretation of Active Directory groups and are mapped to another system by some function over its attributes.

This logic was also highly volatile; writing the rules down became a discovery process, and admins needed to change them live. This was all on top of the underlying challenge of synchronizing data between systems. My solution back then was to handle some of this logic in a component called "Blueprints" that interpreted declarative rules and exposed this logic to other workflows.

The Evolution:

That "Blueprints" component stuck in my mind. About a year later, I decided to tackle the problem more fundamentally with Kumi. My first attempts were brittle—first runtime lambdas, then a series of interpreters. I knew what an AST was, but had to discover concepts like compilers, IRs, and formal type/shape representation. Each iteration revealed deeper problems.

The core issue was my AST representation wasn't expressive enough, forcing me into unverifiable 'runtime magic'. I realized the solution was to iteratively build a more expressive intermediate representation (IR). This wasn't a single step: I spent two months building and throwing away ~5 different IRs, tens of thousands of lines of code. That painful process is what forced me to learn what it truly meant to compile, represent complex shapes, normalize the dataflow, and verify logic. This journey is what led to static type-checking as a necessary outcome, not just an initial goal.

This was coupled with the core challenge: business logic is often about complex, nested, and ragged data (arrays, order items, etc.). If the DSL couldn't natively handle loops over this data, it was pointless. This required an IR expressive enough for optimizations like inlining and loop fusion, which are notoriously hard to reason about with vectorized data.

You can try a web-based demo here: https://kumi-play-web.fly.dev/?example=monte-carlo-simulatio...

And the repo is here: https://github.com/amuta/kumi