ingestlayer/docs/v0.4

docs · 03 actions & templates

Template syntax.

The dialect used by the transform action and the filter field references. Looks like JSON, allows unquoted keys, and substitutes a handful of $-rooted refs with values pulled from the running pipeline context.

Example

One template, one event.

transform · template↵ copy
{
  id:      $event.id,
  email:   $event.payload.email,
  plan:    $entity.user.plan,
  intent:  $classify.intent,
  summary: $summarize.text,
  company: $enrich.company.name,
  sent_at: now()
}

Renders to:

rendered · POST body↵ copy
{
  "id":      "evt_01HZK4...",
  "email":   "ada@example.com",
  "plan":    "growth",
  "intent":  "hot_lead",
  "summary": "Asking about pricing for the enterprise tier.",
  "company": "Acme",
  "sent_at": "2026-05-21T14:03:11.512Z"
}

The six roots

What you can reference.

Paths

Dotted, identifier segments only.

After the root, address into nested objects with dots: $event.payload.email, $entity.user.account_owner. Segments must be valid identifiers (letters, digits, underscores, no array index access yet). A path that doesn't resolve substitutes undefined — which JSON-encodes as null.

now()

The only function.

now() substitutes an ISO timestamp (UTC) at render time. Useful for stamping events with a delivery time, or as a downstream sent_at field.

How substitution works

Four passes, in order.

  1. now() → JSON-encoded timestamp.
  2. Dotted refs ($event.foo.bar) → JSON-encoded value at that path.
  3. Bare roots ($event, $entity) → JSON-encoded object.
  4. Bare object keys → quoted, so the final string parses as JSON.

Values are JSON-encoded on substitution — so a string field comes out quoted, a nested object expands to {...}, and the final rendered string parses cleanly. This is structural by design; the dialect is not meant for prose interpolation like Hello $event.name (you'd get Hello "Ada").

In filter conditions

Same refs, no JSON encoding.

Filter conditions reference the same $-rooted paths in their field column. Values are compared as strings for equality, coerced to numbers for ordered ops, and split on commas for in. Same resolver, different output mode.


all twelve actionsback to docsnext: TypeScript SDK