Kumi is a declarative DSL for building calculation systems.
Schemas define:
- Input shape (scalars, arrays, nested structures)
- Declarations (computed values and boolean conditions)
- Dependencies between declarations
The compiler:
- Performs type checking
- Detects unsatisfiable constraints
- Determines evaluation order
- Generates code for Ruby or JavaScript
Calculation systems appear in: tax engines, pricing models, financial projections, compliance systems, insurance underwriting, shipping rate calculators.
Status: experimental. Public API may change. Typing and some static checks are still evolving.
Feedback: have a use case or hit a rough edge? Open an issue or reach out.
A single schema computes federal, state, FICA taxes across multiple filing statuses. See the interactive demo or inspect the full schema, input, output, and generated code.
Schema
schema do
input do
float :income
float :state_rate
float :local_rate
float :retirement_contrib
string :filing_status
array :statuses do
hash :status do
string :name
float :std
float :addl_threshold
array :rates do
hash :bracket do
float :lo
float :hi # -1 = open-ended
float :rate
end
end
end
end
end
# shared
let :big_hi, 100_000_000_000.0
let :state_tax, input.income * input.state_rate
let :local_tax, input.income * input.local_rate
# FICA constants
let :ss_wage_base, 168_600.0
let :ss_rate, 0.062
let :med_base_rate, 0.0145
let :addl_med_rate, 0.009
# per-status federal
let :taxable, fn(:max, [input.income - input.statuses.status.std, 0])
let :lo, input.statuses.status.rates.bracket.lo
let :hi, input.statuses.status.rates.bracket.hi
let :rate, input.statuses.status.rates.bracket.rate
let :hi_eff, select(hi == -1, big_hi, hi)
let :amt, fn(:clamp, taxable - lo, 0, hi_eff - lo)
let :fed_tax, fn(:sum, amt * rate)
let :in_br, (taxable >= lo) & (taxable < hi_eff)
let :fed_marg, fn(:sum_if, rate, in_br)
let :fed_eff, fed_tax / fn(:max, [input.income, 1.0])
# per-status FICA
let :ss_tax, fn(:min, [input.income, ss_wage_base]) * ss_rate
let :med_tax, input.income * med_base_rate
let :addl_med_tax, fn(:max, [input.income - input.statuses.status.addl_threshold, 0]) * addl_med_rate
let :fica_tax, ss_tax + med_tax + addl_med_tax
let :fica_eff, fica_tax / fn(:max, [input.income, 1.0])
# totals per status
let :total_tax, fed_tax + fica_tax + state_tax + local_tax
let :total_eff, total_tax / fn(:max, [input.income, 1.0])
let :after_tax, input.income - total_tax
let :take_home, after_tax - input.retirement_contrib
# array of result objects, one per status
value :summary, {
filing_status: input.statuses.status.name,
federal: { marginal: fed_marg, effective: fed_eff, tax: fed_tax },
fica: { effective: fica_eff, tax: fica_tax },
state: { marginal: input.state_rate, effective: input.state_rate, tax: state_tax },
local: { marginal: input.local_rate, effective: input.local_rate, tax: local_tax },
total: { effective: total_eff, tax: total_tax },
after_tax: after_tax,
retirement_contrib: input.retirement_contrib,
take_home: take_home
}
endgem install kumiRequires Ruby 3.1+. No external dependencies.
require 'kumi'
Kumi.configure do |config|
config.compilation_mode = :jit
config.cache_path = File.expand_path("tmp/kumi_cache", __dir__)
end
module Double
extend Kumi::Schema
schema do
input { integer :x }
value :doubled, input.x * 2
end
end
# Execute in Ruby
result = Double.from(x: 5)
result[:doubled] # => 10
# or just call the method directly
Double._doubled(x: 5) # => 10
# Export to JavaScript (same logic)
Double.write_source("output.mjs", platform: :javascript)Try the interactive demo (no setup required).
- Syntax Reference - DSL syntax, types, operators, functions, and schema imports
- Functions Reference - Auto-generated docs for all functions and kernels
- functions-reference.json - Machine-readable format for IDEs (VSCode, Monaco, etc.)
- Development Guide - Testing, debugging, and contributing
To regenerate function docs: bin/kumi-doc-gen
MIT License. See LICENSE.