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.
Disclosure (AI-assisted): the English text of this post was drafted with an LLM from my Japanese originals and reviewed by me before publishing. Every code example and its output was executed by the reference implementation; the numbers are measured, not written.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.