Today I tagged 1.0 of Kairos, a schedule
definition language I've been building — a small DSL where schedules like "3 business days
before month-end" or "payday on the 25th, previous business day if it's a holiday" are single
expressions.
premise US { calendar-system: Gregorian; calendar: NYSE; tz: "America/New_York"; wkst: Sun }
@US
monthEnd |> roll(Preceding, on: bizDay) |> shift(-3, unit: bizDay)
The itch
cron can say "the 25th". It cannot say "the 25th, rolled back onto business days". Quartz has
L and LW, but they don't compose and don't know about holidays. RRULE was designed as an
exchange format, not an expression language.
The root problem isn't a missing feature — their expressions don't compose. You can't take
the dates one rule derives and feed them into the next rule. Kairos is built around closure:
every expression maps a time stream to a time stream, so derived streams (substitute holidays,
fiscal periods, lunisolar months) feed further definitions.
Try it in your browser
The reference implementation runs client-side; nothing leaves the page.
- Payday: the 25th → previous business day (US federal holidays)
- 3 business days before month-end
- Deriving the observed federal holidays from the statutory dates alone — July 4, 2026 lands on a Saturday; the expression yields July 3. No lookup table of observed dates anywhere.
What's different from a date library
Temporal, date-fns, dateutil are arithmetic over points and durations. Kairos is one layer
up: it defines and governs sets of instants (streams).
- Calendars are user-defined. The Gregorian calendar itself is a transparent stdlib written in Kairos. Fiscal calendars (4-4-5 included), trading calendars, and the Japanese lunisolar calendar are ordinary definitions, not built-ins. Derivation rules — like the observed-holiday expression above, or Japan's substitute-holiday law — live in the definition, not in a pre-expanded table.
- A definition denotes a set of instants. Evaluation is a pure function — missed fires during downtime are enumerable, audits are reproducible. This has now survived a summer of production use by an independent implementation (schedule predictions stable across 10 hostnames and a local→VPS migration).
-
When calendar data runs out, the results say so — machine-readable annotations
(
covering/ freshness) instead of silent degradation. - Mistakes are static errors with fix-it guidance: mixing civil-day and elapsed-hour widths, undeclared timezones or week starts, misaligned streams, unknown named arguments.
What 1.0 means
The language is frozen: semantics, the operator family, the grammar (EBNF), and the lexis.
Definitions that parse today keep their meaning. The reference implementation stays honest
about what it is — a prototype (TypeScript, zero runtime deps; 638 tests including doctests:
every example in the docs is executed in CI).
The documentation is canonical in Japanese — I develop documentation-first in my native
language — with a full English mirror of the spec, operator reference, and stdlib guides.
Evaluator error messages are currently Japanese (the CLI's --json output is language-neutral).
Apache-2.0.
Links
- Repo: https://github.com/azathothx/kairos-lang
- Recipes — schedules cron and RRULE can't express: https://kairos-lang.org/en/recipes/
- English spec: https://kairos-lang.org/en/spec/
- Install:
npm i -g kairos-lang→kairos next -n 3 payday.kairos
I'd love feedback — especially schedules you've needed that didn't fit existing tools. Issues
in English are welcome.
Top comments (0)