Eventum Logo

Eventum

Eventtemplate

State

Persistent state scopes (locals, shared, globals) in Jinja2 templates.

Templates can store and retrieve values that persist across renders. State is organized into three scopes:

ScopeVariableVisibilityThread safetyTypical use
LocallocalsCurrent template onlySingle-threadedPer-template counters, accumulators
SharedsharedAll templates in one generatorSingle-threadedCross-template coordination, session tracking
GlobalglobalsAll generators in the applicationThread-safe (RLock)Global counters, inter-generator data

locals and shared belong to templates. globals does not: it is the state of the whole event stage, and the script plugin receives the same object in its produce function, so a template and a script coordinate through the same keys.

State API

All three scopes provide the same methods:

MethodSignatureDescription
get(key, default=None) → AnyGet a value. Returns default if the key doesn't exist.
set(key, value) → NoneSet a value.
pop(key, default=None) → AnyRemove a key and return its value. Returns default if the key doesn't exist.
update(mapping) → NoneSet multiple values at once from a dict.
clear() → NoneRemove all values.
as_dict() → dictGet a shallow copy of the entire state.
[key]bracket accessSame as get(key).

The globals scope has three additional methods for manual locking:

MethodDescription
acquire()Acquire the state lock.
release()Release the state lock.
release_if_held()Release every hold the calling thread has on the state lock, and return how many were released.

Individual globals operations (get, set, etc.) are already thread-safe. Use acquire() / release() only when you need multiple operations to execute atomically — for example, reading a counter and incrementing it without another generator modifying it in between.

The lock is never held between events: a hold left behind — including one left by a render that failed before reaching release() — is released once the event is over, so it cannot block other generators. The same holds for every plugin that takes the lock, not only templates.

Use Scenarios in Eventum Studio to visualize which generators read and write global state keys, and to manage global state values at runtime.

Previewing events — in Studio, over the API or through MCP — runs against this same state, so a preview that writes a key changes what running generators read. Values written by a preview persist until they are overwritten or cleared.

Examples

Per-template counter with locals:

{%- do locals.set('n', locals.get('n', 0) + 1) -%}
Event #{{ locals.get('n') }} at {{ timestamp.isoformat() }}

Monotonic record ID with shared — a common pattern where all templates in a generator share a single incrementing counter:

{%- set record_id = shared.get('record_id', 1) -%}
... use record_id in the event body ...
{%- do shared.set('record_id', record_id + 1) -%}

Atomic compound operation with globals:

{%- do globals.acquire() -%}
{%- set total = globals.get('total', 0) -%}
{%- do globals.set('total', total + 1) -%}
{%- do globals.release() -%}

On this page