Deferral
The "not now" primitive - pure snooze presets with energy-aware default ordering.
Deferring an item is an energy statement: it declares insufficient capacity for it right now and names when it should resurface. The SDK models this with pure presets - (now) => Date functions - plus a strategy that orders them by energy level so the one-tap default matches capacity.
The presets
createDeferralPresets builds the standard set. Times are computed in local time - "tomorrow morning" means the user's morning:
import { createDeferralPresets } from '@kumbatio/energy-system'
const presets = createDeferralPresets({ morningHour: 9, eveningHour: 18 })
// both options optional; defaults are 9 and 18| Preset id | Label | Resurfaces |
|---|---|---|
in-1-hour | In 1 hour | now + 60 minutes |
this-evening | This evening (18:00) | today at eveningHour, or tomorrow if already past |
tomorrow-morning | Tomorrow morning (9:00) | tomorrow at morningHour |
next-workday | Next workday (9:00) | next non-weekend day at morningHour |
next-monday | Next Monday (9:00) | next Monday at morningHour |
The stable ids are exported as DEFERRAL_PRESET_IDS so configs and strategies can reference them without magic strings:
import { DEFERRAL_PRESET_IDS } from '@kumbatio/energy-system'
DEFERRAL_PRESET_IDS.tomorrowMorning // 'tomorrow-morning'Resolving a deferral
resolveDeferral maps a preset id to a resurface timestamp (epoch ms). Unknown ids return null - the caller decides whether that's an error:
import { resolveDeferral } from '@kumbatio/energy-system'
const resurfaceAt = resolveDeferral(presets, 'tomorrow-morning')
// number (epoch ms), or null for an unknown id
// Deterministic in tests: pass the reference moment
resolveDeferral(presets, 'next-monday', new Date('2026-07-21T10:00:00'))Storing and resurfacing the item at that timestamp is your app's job - the SDK computes when, deliberately staying out of where your items live.
Energy-aware ordering
deferralStrategy resolves the presentation order and the one-tap default for the current level:
import { deferralStrategy } from '@kumbatio/energy-system'
const { defaultPresetId, orderedPresetIds } = engine.resolve(deferralStrategy)| Level | Default | Reasoning |
|---|---|---|
100 | in 1 hour | High capacity - short deferrals are realistic |
75 | in 1 hour | |
50 | this evening | Push past the current stretch |
25 | tomorrow morning | Resurface when capacity has plausibly recovered |
0 | tomorrow morning | Not in an hour - you're resting |
orderedPresetIds lists all five, most-prominent first, so a snooze menu can render them in capacity-appropriate order.
Putting it together
import {
createDeferralPresets,
deferralStrategy,
resolveDeferral,
} from '@kumbatio/energy-system'
const presets = createDeferralPresets()
function snooze(itemId: string) {
const { defaultPresetId } = engine.resolve(deferralStrategy)
const resurfaceAt = resolveDeferral(presets, defaultPresetId)
if (resurfaceAt !== null) {
saveSnooze(itemId, resurfaceAt)
}
}Deferral presets compute times; they hold no state. If you also route the item's notification through the gate, the defer-not-drop guarantee applies when it resurfaces at a low-energy moment.
