Declaring a module
Modules are declared inpolicy.yaml, with their contract stated up front:
policy.yaml
def handle(input) taking a
dict and returning a JSON-compatible dict. The harness owns all transport; author code never
reads stdin, writes stdout, or touches bindings:
modules/renderer.py
kind: wasm instead:
kind: wasm runs your compiled module through
the same engine. Either way:
- the declared digest pins the exact bytes into the bundle at compile time
- execution is metered by the declared limits
- the sandbox has no I/O — no filesystem, network, clock, or randomness
Calling a module
A handler runs itsrules: before deciding what to do; a compute-module rule runs there and
stores its result in computed.*, which lives only for that handler:
nodes.yaml
inputvalues are simple explicit paths rooted inpayload,entity,event, orcomputed— no expressions smuggled in.intomust targetcomputed.*. Module output is handler context, not state: persisting it requires an explicitdata_accumulationwrite, with its own owner.- A module row cannot emit, advance state, run actions, fan out, or touch entity state — it computes a value, full stop.
- An unconsumed
intobinding is a boot error: if nothing downstream reads the value, the declaration is dead and verify says so.
When to reach for one
A compute module is an escape hatch that stays inside the model: logic beyond what rows can
express, still deterministic, still verified, still replayable.

