Deadlines, reminders and escalation
Rungs never reads the system clock. You pass clock, and time-based actions happen when you call
rungs.tick(). That keeps behavior reproducible: the same state, command and time always give the
same result, and tests can move time forward.
let now = new Date("2026-03-02T09:00:00.000Z");const rungs = createRungs({ store: memoryStore(), clock: () => now, // Rungs never reads the time itself ids: () => crypto.randomUUID(), roles: (role) => (role === "director" ? ["u_dir"] : []), onEvent: (event) => { if (event.type === "task.reminder") console.log("remind", event.data.assigneeId); },});Runs in CI:examples/docs-snippets/src/concepts/deadlines.ts
A step with a deadline says what happens when nobody decides in time:
{ id: "manager", approvers: { type: "users", ids: ["u_mgr"] }, deadline: "P2D", // two days after the step starts remindBefore: "P1D", // one reminder a day before onTimeout: "escalate", // or "remind", "auto-approve", "auto-reject" escalateTo: { type: "role", role: "director" },},Runs in CI:examples/docs-snippets/src/concepts/deadlines.ts
onTimeout |
At the deadline |
|---|---|
"remind" (default) |
Reminds the approvers, then every remindOverdueEvery (default one day) |
"escalate" |
Gives the open tasks to escalateTo, with a new deadline |
"auto-approve", "auto-reject" |
Decides the step; never overrides a rejection already cast |
Durations are ISO 8601 ("PT8H", "P2D", "P1W"); months and years are not allowed because
their length varies. For business days, pass a calendar (EC-30).
Running tick
Section titled “Running tick”// Run tick on a schedule, for example every minute. It applies whatever is due at `now`.now = new Date("2026-03-03T10:00:00.000Z");ticks.push(await rungs.tick()); // remind u_mgrnow = new Date("2026-03-04T10:00:00.000Z");ticks.push(await rungs.tick()); // escalated: the task moves to u_dirRuns in CI:examples/docs-snippets/src/concepts/deadlines.ts
tick is safe to run twice or from several workers at once: each due action is applied once
(EC-27). Run it on a schedule, for example every minute.
Escalation never lets one person replace several votes: in an all or quorum step that still
needs more than one approval, a single escalation target is not enough and Rungs reports
request.escalation_failed instead (EC-28).