Generator reference
Every built-in generator type and its parameters, verified against crates/pgdl/src/generators/*.rs, compile.rs, and composition.rs. For the readable guide see Generators (PGDL); for a worked gallery see the generator gallery.
The envelope
The engine runs a uniform envelope — { use, params, constraints, modifiers } — but a PGDL definition is authored per-type and compiled to it. The two authoring forms:
{ "type": "logic", "algorithm": "int_between", "params": { "min": 1, "max": 9 } }{ "use": "@phony/core:logic.int_between", "params": { "min": 1, "max": 9 } }type maps to a built-in reference; use names any registered generator directly (the open-set escape hatch for custom/packaged generators). The PGDL type → reference mapping:
type | Reference | Keys gathered into params |
|---|---|---|
logic | @phony/core:logic.<algorithm> | params (verbatim) |
list | @phony/core:list | source, values, key, where |
model | @phony/core:model | source, generation |
statistical | @phony/core:statistical | mode, values, distribution, params, differential_privacy, variables, correlations |
event_sequence | @phony/core:event_sequence | events |
The template and linked types were folded into composition and now error with guidance (author a composition body/variants, or a list over an asset).
Modifiers
Cross-cutting filters applied to any generator's output, set as top-level keys on a PGDL definition.
| Modifier | Type | Effect |
|---|---|---|
unique | boolean | Emit distinct values across rows. Re-rolls on a collision (up to 200 attempts) then errors if it cannot. Nulls are exempt (they neither enter the dedup set nor burn attempts). |
nullable | boolean or number | Probability of emitting null. true uses the default rate 0.1; a number is an explicit rate in [0, 1]. Drawn on a dedicated sub-stream so it never perturbs the value stream. |
transform | string (PEL) | A PEL expression applied to the produced value, with value bound to it. |
{ "type": "logic", "algorithm": "int_between", "params": { "min": 1, "max": 1000 },
"unique": true, "nullable": 0.05, "transform": "format(value, 'number')" }Logic
Pure algorithms, no data source, locale-independent. One algorithm per definition, selected by algorithm. Every value is a pure function of the cell seed (and, for sequence, the row index).
algorithm | Output | Parameters (default) |
|---|---|---|
uuid_v4 | string | — |
uuid_v7 | string | — (synthetic, index-sortable timestamp = reference instant + index) |
ulid | string | — (26-char Crockford base32) |
nanoid | string | length (21) |
int_between | integer | min (0), max (2147483647), except (array, none) |
float_between | number | min (0), max (1), precision (2) |
boolean | boolean | probability (0.5, clamped to [0,1]) |
datetime_between | string | start (1970-01-01), end (2038-01-01) |
date_between | string | start (1970-01-01), end (2038-01-01) |
time_between | string | start (00:00:00), end (23:59:59) |
timestamp | integer | start (1970-01-01), end (2038-01-01) — Unix seconds |
sequence | integer | start (1), step (1) → start + row·step |
gaussian | number | mean (0), stddev (1) — rounded to 6 decimals |
exponential | number | lambda (1) — rounded to 6 decimals |
digits | integer or string | digits (1, clamped 1–18), strict (false), leading_zero (false) |
Notes:
int_betweenerrors ifmin > max.exceptis a list of values to avoid; it errors if it excludes the whole range or cannot avoid the set within 1000 tries.float_betweenerrors ifmin > max.datetime_between/date_between/timestampbounds accept ISO-8601 or relative specs (now,today,-1year,now+7days); bounds are ordered so either direction works.time_betweenbounds areHH:MM:SS/HH:MM.digits: the value spans[min, 10^digits − 1], whereminis10^(digits−1)whenstrict, else0.leading_zeroreturns a zero-padded string; otherwise an integer.
{ "type": "logic", "algorithm": "digits", "params": { "digits": 4, "strict": true, "leading_zero": true } }List
Select from a finite set (inline or an asset), optionally keyed or filtered. Selection is inverse-CDF weighted, so it follows weights exactly and reproducibly.
| Parameter | Type | Description |
|---|---|---|
values | array | Inline candidate set. |
source | string or object | Asset reference: a non-"inline" string name, or { "asset": name }. "inline" (or omitted) means use values. |
key | string | When the source is a map, pick from the source[key] bucket (must be an array). |
where | string (PEL) | Predicate evaluated per element with item bound to the candidate (plus the caller's bindings). Keeps matching elements, then picks. |
Element shapes:
- a plain scalar — returned as-is;
{ value, weight }— unwraps tovalue;weightdefaults to1,0means never selected (kept but excluded from the draw);- any other object (metadata record) — returned whole.
An empty selection (nothing matched), or all-zero weights, is an error. A missing key bucket is an error.
{ "type": "list", "source": "districts", "key": "{{ city }}",
"where": "item.population > 100000" }Model
Delegate to the trained N-gram engine. The model is an asset resolved by name. Output is a pure function of the cell seed. See the .ngram format.
| Parameter | Type | Description |
|---|---|---|
source | string (required) | The model asset name. |
generation | object | { mode, params }. mode defaults to word. |
generation.mode and its params:
mode | params (default) | Notes |
|---|---|---|
word | — | Honours the top-level constraints. |
sentence | word_count (learned), punctuation ("."; string or array to pick from), starts_with | — |
text | max_chars (200), suffix (""), starts_with | Prose up to max_chars. |
paragraph | sentence_count (learned), starts_with | — |
poem | verses (4), stanza_length (4), max_words (8) | — |
acrostic | initials (""), max_words (8) | An unsatisfiable initial errors (no silent fallback). |
real_word | prefix (none) | Samples an actual training item; null if none matches. |
starts_with may come from generation.params or fall back to the top-level constraints.
Top-level constraints (applied where the mode supports them):
| Constraint | Type | Description |
|---|---|---|
starts_with | string | Require a prefix. |
ends_with | string | Require a suffix. |
contains | string | Require a substring. |
min_length | integer | Minimum length. |
max_length | integer | Maximum length. |
exclude_originals | boolean (false) | Never emit a verbatim training item. |
{ "type": "model", "source": "first_names",
"generation": { "mode": "word" }, "constraints": { "min_length": 3, "starts_with": "M" } }Statistical
Distribution-matching values. mode defaults to continuous.
mode | Output | Purpose |
|---|---|---|
categorical | any | Frequency-preserving weighted pick. |
continuous | number | Sample a named distribution. |
multivariate | object | Correlated draws. |
algebraic | — | Not a generator mode: express it with a composition let/computed step (errors with that guidance). |
categorical
| Parameter | Type | Description |
|---|---|---|
values | array (required) | Elements { value, weight }; weight defaults to 1, 0 = never. All-zero (or empty) errors. |
continuous
| Parameter | Type | Description |
|---|---|---|
distribution | string (normal) | The distribution to sample. |
params | object | Distribution parameters (below). |
differential_privacy | object | Optional DP noise (below). |
Constraints min / max (top-level constraints) form a window: the value is resampled up to 50 times to land inside it, then clamped. The result is rounded to 6 decimals.
Distributions and their params (defaults):
distribution | Parameters |
|---|---|
normal | mean (0), stddev (1) |
lognormal | mu (0), sigma (1) |
exponential | lambda (1) |
uniform | min (0), max (1) |
poisson | lambda (1) |
beta | alpha (1), beta (1) |
gamma | shape (1), scale (1) |
differential_privacy object:
| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Turn DP noise on. |
epsilon | number | 1.0 | Privacy budget (floored at 1e-6). |
sensitivity | number | 1.0 | Query sensitivity. |
mechanism | string | laplace | laplace or gaussian. |
DP noise is drawn on its own stream so it never disturbs the value stream.
multivariate
| Parameter | Type | Description |
|---|---|---|
variables | array (required) | Each { name, mean (0), stddev (1) }. Names must be non-empty and unique. |
correlations | array | An N×N correlation matrix (default identity). Must be square and positive-definite. |
Returns an object { name: value, … }, values rounded to 6 decimals, drawn jointly via a Cholesky factorization of the correlation matrix.
{ "type": "statistical", "mode": "continuous", "distribution": "lognormal",
"params": { "mu": 3, "sigma": 0.5 }, "constraints": { "min": 0 } }Event sequence
Chronologically valid date series. Returns an object mapping each event name to an ISO-8601 datetime, or null when an optional event is skipped or its predecessor was skipped.
| Parameter | Type | Description |
|---|---|---|
events | array (required, ≥1) | The event definitions. |
Each event object:
| Key | Type | Description |
|---|---|---|
name | string (required) | The event's key in the output. |
base | boolean | Marks an anchor event that lands in range. |
range | object | { start, end } for a base/anchor event (ISO or relative specs). |
after | string | Name of the predecessor; this event is the predecessor plus a delay. |
probability | number | Gate in [0, 1]: below the roll, the event (and dependents) is skipped (null). Rolled on a dedicated sub-stream. |
delay | object | { min, max } durations added to the predecessor. |
Rules: the sequence needs an anchor (an event with base: true or with no after); an after must name a defined event (both checked statically). A delay duration is a number plus a unit — s (or empty), m, h, d, w (e.g. 1d, 24h, 2w).
{ "type": "event_sequence", "events": [
{ "name": "signup", "base": true, "range": { "start": "-1year", "end": "now" } },
{ "name": "first_purchase", "after": "signup", "probability": 0.6, "delay": { "min": "1d", "max": "30d" } }
] }Composition
A generator authored as pure data (PGDL + PEL) — how a generator is made of other generators, nested without limit. Registered by name, then usable exactly like a built-in. Its params are validated against its own manifest on every call.
{
"name": "@acme/finance:net",
"version": "0.1.0",
"description": "Net amount after tax.",
"params": { "rate": { "type": "number", "default": 0.18 } },
"let": {
"subtotal": { "type": "logic", "algorithm": "float_between", "params": { "min": 10, "max": 500 } },
"tax": { "computed": "round(subtotal * rate, 2)" }
},
"body": "{{ subtotal + tax }}"
}| Field | Type | Description |
|---|---|---|
name | string (required) | Namespaced generator name. |
version | string (0.1.0) | Manifest version. |
description | string | Manifest summary. |
params | object | Input params: each { type, required (false), default }. |
let | object | Named steps, evaluated in dependency order (topologically sorted; a cycle errors). |
body / variants / output | — | Exactly one output form (below). |
Everything a composition references resolves against its own local bindings (its params + let results) — never a table, row, or sibling field. Every reference is checked at registration against the known param/let names (a where predicate may also use item); a typo fails then, not at run time.
let step forms
| Form | Shape | Result |
|---|---|---|
| Generator | any generator definition ({ type … } or { use … }) | The sub-generator's value. Its string params are PEL templates evaluated against the locals, so parent values thread through. |
| Computed | { "computed": "<PEL expression>" } | The expression's value (bare expression over prior locals). |
| Repeat | { "repeat": { count, of, unique? } } | An array of count sub-generator outputs. |
The repeat step (the "N items per parent" primitive):
| Key | Type | Description |
|---|---|---|
count | integer, "a-b" range string, or PEL expression string | How many items. A range draws one integer per invocation; an expression resolves over the locals (floored to an integer). |
of | generator definition | The item generator; its params are interpolated against the locals so items can reference the parent. |
unique | boolean (false) | De-duplicate items, with up to 200 retries each; failing to fill errors. |
Output forms
| Field | Type | Output kind |
|---|---|---|
body | template string | string (the rendered template) |
variants | array of { pattern, weight? } | string — a weighted choice among body templates. weight defaults to 1, 0 = never; empty or all-zero errors. |
output | structured JSON | object / array / any — string leaves are evaluated against the locals (a whole-expression leaf keeps its native type). |
{
"name": "@acme/orders:order",
"let": {
"id": { "type": "logic", "algorithm": "uuid_v4" },
"lines": { "repeat": { "count": "1-5", "of": { "type": "logic", "algorithm": "int_between", "params": { "min": 1, "max": 9 } } } }
},
"output": { "order_id": "{{ id }}", "quantities": "{{ lines }}" }
}