SYNTAX.md
Scope
This document defines the user-facing schedule syntax accepted by Kron. The same syntax is used by:
Kubernetes CRDs (
KronJob.spec.schedule,KronJob.spec.window,KronJob.spec.distribution,KronJob.spec.constraints)krontabentries forkrond
The syntax is designed to be:
Cron-compatible for the baseline schedule
Explicit for probabilistic extensions
Deterministic and fully parseable
Grammar overview
A Kron schedule is composed of:
A baseline cron expression
Optional modifiers
Canonical form:
<cron> [@tz(<tz>)] [@win(<mode>,<duration>)] [@dist(<name>[,<k=v>...])] [@seed(<strategy>[,<k=v>...])] [@policy(<k=v>...)] [@avoid(<spec>)] [@only(<spec>)]
Order of modifiers is not significant.
Whitespace separates tokens. Parentheses do not contain unescaped whitespace.
Cron expression
Kron accepts standard 5-field cron:
<minute> <hour> <day-of-month> <month> <day-of-week>
Ranges, lists, and steps are supported:
*nn-mn,m,k*/sn-m/s
Aliases are supported where common:
months:
JAN..DECweekdays:
SUN..SAT
Day-of-week values:
0-6with0=SUNSUN..SAT
Examples:
0 0 * * * # daily at midnight
15 9 * * MON-FRI # weekdays at 09:15
*/5 * * * * # every 5 minutes
0 3 1 * * # monthly on the 1st at 03:00
Timezone modifier
@tz(<tz>)
<tz> is an IANA timezone name.
Examples:
0 10 * * * @tz(Europe/Paris)
0 18 * * * @tz(America/Los_Angeles)
If omitted, timezone is UTC.
Window modifier
@win(<mode>,<duration>)
<mode>:
afteraround
<duration> is a Go-style duration:
ns,us,ms,s,m,hcomposite forms are allowed:
1h30m
Semantics:
after: window is[nominal, nominal + duration]around: window is[nominal - duration/2, nominal + duration/2]
Examples:
0 0 * * * @win(after,2h)
0 10 * * * @win(around,45m)
If omitted, window is after,0s.
Distribution modifier
@dist(<name>[,<k=v>...])
<name>:
uniformnormalskewEarlyskewLateexponential
Parameters are k=v pairs. Unknown keys are invalid.
MVP runtime status:
krontab explainandkrontab nextexecute:uniform,skewEarly,skewLatenormalandexponentialare syntax-valid and lint-validated, but runtime execution is not part of current MVP
uniform
@dist(uniform)
No parameters.
normal
@dist(normal[,mu=<anchor>][,sigma=<duration>])
MVP runtime note: syntax-valid and lint-validated, but not executed by krontab explain/krontab next.
musets the mean anchor point.sigmasets standard deviation.
mu anchors:
nominalstartmidend
Defaults:
mu=nominalforaroundmu=midforaftersigma=window/6
Examples:
0 10 * * * @win(around,2h) @dist(normal,sigma=20m)
0 10 * * * @win(after,2h) @dist(normal,mu=start,sigma=15m)
skewEarly / skewLate
@dist(skewEarly[,shape=<float>])
@dist(skewLate[,shape=<float>])
shapecontrols skew intensity.shapeis a positive float.default
shape=2.0
Examples:
0 10 * * * @win(after,2h) @dist(skewEarly,shape=3)
0 10 * * * @win(after,2h) @dist(skewLate,shape=1.5)
exponential
@dist(exponential[,lambda=<float>][,dir=<dir>])
MVP runtime note: syntax-valid and lint-validated, but not executed by krontab explain/krontab next.
lambdais a positive float controlling decay rate.dir:earlybiases toward window startlatebiases toward window end
defaults:
lambda=1.0,dir=early
Examples:
0 10 * * * @win(after,2h) @dist(exponential,dir=early,lambda=1.2)
0 10 * * * @win(after,2h) @dist(exponential,dir=late,lambda=0.8)
If omitted, distribution is uniform.
Seed modifier
@seed(<strategy>[,<k=v>...])
<strategy>:
stabledailyweekly
Parameters:
salt=<string>
<string> is a UTF-8 string without unescaped whitespace. Quoted strings are supported:
"..."with\"escapes
Examples:
0 0 * * * @seed(stable,salt="team-a")
0 10 * * * @seed(daily)
0 10 * * MON @seed(weekly,salt=prod)
If omitted, seed strategy is stable with empty salt.
Policy modifier
@policy(<k=v>[,<k=v>...])
Keys:
concurrency=allow|forbid|replacedeadline=<duration>suspend=true|false
Defaults:
concurrency=forbiddeadline=0s(skip missed periods)suspend=false
Examples:
0 0 * * * @policy(concurrency=forbid,deadline=10m)
0 10 * * * @policy(concurrency=replace)
Constraints modifiers
Constraints restrict when a chosen time may be selected. Constraints apply after the window is computed and before a final time is accepted. If a candidate time violates constraints, a new candidate is drawn. If no valid time can be found, the period is unschedulable.
Avoid modifier
@avoid(<spec>)
Only modifier
@only(<spec>)
A constraint spec is a semicolon-separated list of clauses:
<clause> ; <clause> ; ...
Clause forms:
hours=<range>dow=<range>dom=<range>months=<range>between=<hh:mm>-<hh:mm>date=<yyyy-mm-dd>dates=<yyyy-mm-dd>..<yyyy-mm-dd>
Ranges:
numeric ranges with lists and hyphens, e.g.
1-5,7,9-12weekdays:
SUN..SATmonths:
JAN..DEC
Time values are interpreted in the schedule timezone.
Examples:
0 10 * * * @win(after,2h) @avoid(hours=0-6)
0 18 * * * @win(around,1h) @only(dow=MON-FRI;between=08:00-20:00)
0 19 * * * @avoid(date=2026-12-25)
0 19 * * * @avoid(dates=2026-12-24..2026-12-31)
Validation rules
Cron expression must be valid and resolvable.
Timezone must be a valid IANA name.
Window duration must be non-negative.
For
aroundmode,duration/2is computed with nanosecond precision.Distributions must be recognized; parameters must be valid and within allowed ranges.
In current MVP runtime, only
uniform,skewEarly, andskewLateare executable inexplain/next.Seed strategy must be recognized.
Policy keys must be recognized; values must be valid.
Constraint specs must be parseable; unknown clause keys are invalid.
@only(...)and@avoid(...)may both be present.If constraints eliminate the entire window, the period is unschedulable.
Examples (MVP executable with explain/next)
Load smoothing (spread backups)
0 0 * * * @tz(UTC) @win(after,3h) @dist(uniform) @seed(stable,salt=backup) @policy(concurrency=forbid,deadline=30m)
Human-like messaging (late-biased)
0 10 * * * @tz(Europe/Paris) @win(around,90m) @dist(skewLate,shape=2.5) @seed(daily,salt=msgs) @only(dow=MON-FRI;between=08:00-20:00)
Home automation (gentle unpredictability)
0 18 * * * @tz(America/Los_Angeles) @win(around,20m) @dist(skewLate,shape=1.4) @seed(daily,salt=lights)
Avoid nights and weekends
0 * * * * @tz(UTC) @win(after,30m) @dist(skewEarly) @only(dow=MON-FRI;hours=8-18)
Monthly with wide window, strict deadline
0 2 1 * * @tz(UTC) @win(after,8h) @dist(uniform) @policy(concurrency=forbid,deadline=15m)
Lint-only Examples (planned runtime distributions)
These pass krontab lint but are not executable by MVP krontab explain/krontab next.
0 10 * * * @win(around,2h) @dist(normal,sigma=20m)
0 10 * * * @win(after,2h) @dist(exponential,dir=early,lambda=1.2)