Kumbatio
Core

Levels

The five built-in level definitions and pure level functions

The five levels

The level model is fixed. getEnergyLevels() returns these definitions, ordered highest to lowest, all deeply frozen:

ValueKeyLabelDescription
100peakPeakHigh capacity. Planning, complex decisions, creative work.
75activeActiveGood capacity. Focused execution, problem-solving.
50steadySteadyModerate capacity. Routine tasks, familiar work.
25lowLowLimited capacity. Simple tasks, review, light work.
0restRestRecovery. Consumption only - reading, reflecting.

Cognitive profiles per level:

LeveldecisionCapacityfocusDurationtaskComplexityinterruptionTolerance
100highextendedcomplexhigh
75moderatemoderatemoderatemoderate
50lowshortroutinelow
25minimalminimalsimpleminimal
0nonenoneconsumptionnone

getEnergyLevels

function getEnergyLevels(): ReadonlyArray<Readonly<EnergyLevelDefinition>>

Get all energy level definitions, ordered highest to lowest (100, 75, 50, 25, 0).

getEnergyLevel

function getEnergyLevel(level: EnergyLevel): Readonly<EnergyLevelDefinition>

Get the definition for a specific energy level. Throws Error('Invalid energy level: ...') for values outside the model.

import { getEnergyLevel } from '@kumbatio/energy-system'

getEnergyLevel(75).label // 'Active'

cycleEnergyLevel

function cycleEnergyLevel(current: EnergyLevel): EnergyLevel

Cycle to the next energy level: 100 -> 75 -> 50 -> 25 -> 0 -> 100. Returns 100 when current is not a known level.

isEnergyLevel

function isEnergyLevel(value: unknown): value is EnergyLevel

Validate that an unknown value is a valid EnergyLevel.

isEnergySource

function isEnergySource(value: unknown): value is EnergySource

Validate that an unknown value is a valid EnergySource.

isHigherEnergy

function isHigherEnergy(a: EnergyLevel, b: EnergyLevel): boolean

Returns true if level a represents higher energy than level b (numeric comparison).

createEnergyOrigin

function createEnergyOrigin(): string

Mint a unique producer identity for deterministic cross-context ordering. Uses crypto.randomUUID() when available, falling back to crypto.getRandomValues() and then to a time-plus-counter string, so it never throws in older runtimes.

The engine calls this internally when you don't pass originId to createEnergyEngine - you only need it yourself to mint a stable per-install identity that survives restarts. Both shipped desktop integrations do exactly that:

import { createEnergyOrigin, createEnergyEngine } from '@kumbatio/energy-system'

function stableOriginId(): string {
  const KEY = 'myapp:energy-origin'
  let id = localStorage.getItem(KEY)
  if (!id) {
    id = `myapp:app:${createEnergyOrigin()}`
    localStorage.setItem(KEY, id)
  }
  return id
}

const engine = createEnergyEngine({ originId: stableOriginId() })

Available since 0.5.4; earlier versions used it internally without exporting it. See Production Patterns for the write-identity discipline around origins and revisions.

createEnergyState

function createEnergyState(
  level: EnergyLevel,
  source?: EnergySource,   // default: 'manual'
  timestamp?: number,      // default: Date.now()
  revision?: number,       // default: module-level auto-incrementing counter
  origin?: string,         // default: a stable per-process random origin id
): EnergyState

Create a frozen EnergyState for the current moment. Intended for standalone use (tests, persistence adapters, external producers); the engine constructs its own states via setLevel.

Validation - each check throws an Error on failure:

ParameterRequirement
levelMust pass isEnergyLevel
sourceMust pass isEnergySource
timestampFinite number, >= 0
revisionSafe integer, >= 0
originNon-empty string
import { createEnergyState } from '@kumbatio/energy-system'

const state = createEnergyState(50, 'scheduled')
// { level: 50, source: 'scheduled', timestamp: ..., revision: ..., origin: '...' }

The unproduced state

An engine starts on a state nobody chose: the initialLevel default, before any user action, persisted value or observed update has replaced it. That default is stamped with sentinels rather than a real clock reading and a real identity.

const UNPRODUCED_TIMESTAMP = 0
const UNPRODUCED_ORIGIN = '0-initial'

Two reasons they exist. Construction reads neither the clock nor the random source, which is what makes building an engine during a React render prerender-safe - Next.js Cache Components fails a build on unstable values baked into static output. And both sentinels sort below any real value, which is also the semantics you want: a persisted or observed state must always beat the default it replaces.

isUnproducedState

function isUnproducedState(state: Pick<EnergyState, 'timestamp' | 'origin'>): boolean

True for the untouched default - its age and identity are not meaningful. Use it before treating state.timestamp as a real moment.

import { isUnproducedState } from '@kumbatio/energy-system'

// Without the guard, an untouched engine reports an age measured from the epoch.
const ageMs = isUnproducedState(state) ? 0 : Date.now() - state.timestamp

getEnergyMetrics already applies this guard, reporting stateAgeMs: 0 for a state nobody has set yet.