Yarunoka

Calendar-aware schedule DSL and pure occurrence query engine.

The name is the Japanese question やるのか?(yaru no ka?) — roughly “so, do we do it?”. That is the question this engine exists to answer.

Yarunoka is looking for a logo and an icon — want to contribute? Reach out on X: @chatii

Calendar rules, not clock rules

Real-world schedules are calendar rules. “Payday is the 25th — moved up to the previous business day when that falls on a weekend or a holiday.” “Collection day is the second Tuesday of every month.” “The poller runs every 90 minutes, but only within business hours.” Cron expressions and plain timestamps cannot carry these rules, so they end up as scattered application code — hard to store, hard to display, and impossible for users to edit safely.

Yarunoka is a small JSON DSL — Yrnk — that states such rules as data, plus an engine that answers questions about them.

A schedule is data

Payday: the 25th, shifted back to the previous business day.

{
    "version": "1.1",
    "timezone": "Asia/Tokyo",
    "calendar": {
        "holidays": ["2026-01-01", "2026-07-20"],
        "business_holidays": [],
        "business_days": []
    },
    "schedules": [
        {"days": [25], "shift": ["prev", "or_same", "business_day"], "times": ["10:00"]}
    ]
}

2026-07-25 is a Saturday, so the payday shifts back to Friday the 24th. Ask the engine:

matches 2026-07-24 10:00
true
matches 2026-07-25 10:00
false

Three parts

Document
A document carries a timezone, a calendar, and a list of schedules. The calendar is the definitions that give meaning to the calendar vocabulary: holidays, business holidays, extra business days, the workweek, business hours, and custom named date sets. A date set is written as a fixed date list or as the name of a resolver the application registers at runtime.
Schedule
A schedule combines a day expression (days of the month, weekdays, ordinal weekdays, calendar words such as holiday, day cycles), an optional shift rule (“the previous business day”), and the times of day (fixed points, grids such as every 90 minutes, or all-day).
Engine
The engine is pure. It executes no jobs and persists no state; it answers “does this date-time match?” and “was there an occurrence in this interval?”. Firing, catch-up, and throttling remain design decisions of the caller.

Get started

PHP

Install with Composer:

composer require yarunoka/core

Requires PHP 8.4 or newer. No runtime dependencies.

PHP (Laravel)

Install with Composer:

composer require yarunoka/laravel

Requires PHP 8.4 or newer and Laravel 13.

TypeScript

Install with npm:

npm install @yarunoka/core

Requires Node.js 26 or newer — or any runtime with the Temporal API, which a polyfill can supply. No runtime dependencies. ESM only.

TypeScript (Headless Builder)

Install with npm:

npm install @yarunoka/builder @yarunoka/core

Requires Node.js 26 or newer — or any runtime with the Temporal API, which a polyfill can supply. @yarunoka/core is a peer dependency. ESM only.

Repositories

Roadmap