derivations.yaml is where those live. Each derivation names one fact, the facts it’s computed from, and exactly one way to compute it — and the runtime recomputes it every turn from live inputs, so a derived value can never go stale mid-conversation.
id— the fact this row produces (declared in the vocabulary withknown_from: derived).means— what the value is, in words a caller could hear.given— the input facts; until they’re established, the derived fact is simply unknown.- One body — how it’s computed. There are four kinds:
The four kinds
A formula (value:) — arithmetic and logic over other facts. Computed exactly (decimal, never float):
decide:) — ordered conditions where the first match wins, so the order is the meaning. otherwise: is mandatory — every ladder says what happens when nothing matches:
table:) — a lookup over one or two enum axes. Because the axes are enums, a missing cell is a build error, not a runtime surprise:
model:) — for the rare value no formula can produce, like a search query built from a caller’s request. This is the one kind computed once and kept, rather than recomputed every turn.
Why derivations matter
Derivations are where policy text becomes computation. A threshold from your methodology, a fee schedule, an eligibility rule — each becomes a row that always computes the same answer from the same inputs, shows its work in the trace, and can name the exact provision it implements withencodes::
needs, gates test them in requires, and replies read them back — so the arithmetic your business runs on is written once, in one file, and enforced everywhere.