Skip to content

Vocabulary

This page introduces the words the rest of the documentation uses. No YAML syntax here — that lives in Authoring Flows. Read this once and the rest reads at full speed.

A flow is the unit of work: a YAML file describing how data moves through a pipeline as a directed acyclic graph — a sequence (or tree) of steps that begins with a typed input, ends with a typed output, and transforms data along the way.

graph TD
    input([typed input]) --> products[fetch products]
    input --> stock[fetch stock]
    products --> join[join]
    stock --> join
    join --> filter[filter active]
    filter --> output([typed output])

A flow is portable: the same flow runs against dev, staging, or production environments without YAML edits. The flow describes what to do; the environment describes which services to do it against. Each time a flow executes is a run — its own UUIDv7 ID, its own log, its own output. Runs are independent and can execute in parallel.

A flow is a sequence of steps. Each step is one of:

  • An action — invokes a connector with a with: block of inputs.
  • A control-flow constructif:, for-each:, switch:. Branches or iterates.
  • A transformerjoin: (relational join), delta: (change detection), filter: (SQL-like array filtering).
  • A built-in verblog:, return:, stop:, set:, $var:.

Steps may be named or unnamed. A named step’s output lands in the payload under that name ($fetch: makes its output available as ${fetch}). Unnamed steps are used when you only care about the side effect — a log: line, an if: condition.

A connector is the verb: a typed, named, versioned function that takes structured input and returns structured output. Examples: zenvara/http, zenvara/mssql, zenvara/sftp, zenvara/ai. Each name is provider-qualified — the part before the / is the publisher.

A connector can have multiple actions. The HTTP connector has get, post, put, delete; the MSSQL connector has query, command, query-cursor. A flow step picks a connector and an action: invoke: http.get, invoke: mssql.query.

Every connector carries a metadata file (<name>.connector.yaml) declaring its actions, typed inputs, typed outputs, and per-action documentation. The Connector Catalog is built from those files.

The payload is the data carried between steps — a map of typed values, each one of five types: Boolean, String, Number, Array, Object. There is no untyped “any”.

Each step’s output is merged back into the payload under the step’s assigned name. After $fetch: runs, the payload contains a fetch entry, and later steps reference fields on it as ${fetch.body}, ${fetch.statusCode}. The payload accumulates as the flow runs; the only data that leaves the flow is what the output: block declares.

graph LR
    p1["payload<br/>{ city }"] -->|$weather| p2["payload<br/>{ city, weather }"]
    p2 -->|$report| p3["payload<br/>{ city, weather, report }"]

A connection is the typed configuration for one external service: a database, an SFTP, an API, a mail server. Each has a type: (which connector family it belongs to), a required kind: (production, staging, development, sandbox, or base for an extends-only template that is never bound directly into an environment), and the parameters that connector needs.

Connections live under config/connections/{name}.connection.yaml. Credentials inside a connection are always references${secret:db/warehouse:password}, never the password itself. The platform refuses to load a connection containing a plain credential.

An environment is a profile of connections. It maps short aliases (db, sftp, audit) onto named connections (warehouse-prod, archive-sftp). A flow asks for db; the environment decides which real connection that resolves to today.

graph LR
    flow["Flow asks &quot;db&quot;"] -->|env: dev| dev["db → warehouse-dev"] --> devhost[dev DB host]
    flow -->|env: prod| prod["db → warehouse-prod"] --> prodhost[prod DB host]

Same flow, two runs, two completely different real services. Environments live under config/environments/{name}.environment.yaml and can extend: other environments.

An environment carries a kind:production, staging, development, or sandbox. kind is a guard tier, not a copy of your infrastructure: it drives cross-environment validation, kind-aware authorization, and the block on ephemeral inline runs. You add an environment for a new deployment target, not for a new connection. See Environments vs Branches.

A secret is a credential kept out of source. Connection and flow YAML reference secrets as ${secret:path} (whole-value) or ${secret:path:key} (sub-key, when one entry has multiple fields like host/username/password).

Secrets are resolved at flow start in a single async batch. If any secret a flow references cannot be resolved, the flow fails before any connector runs — there is no half-failed state. Two providers: an encrypted file (AES-256-GCM, single-host) or HashiCorp Vault.

A trigger is what kicks a flow off. The platform supports cron schedules, HTTP webhooks, AWS SQS, mail, filesystem watch, log monitoring, and flow-to-flow triggering. A flow can have multiple triggers — fired by a cron at 09:00 and by a webhook on demand and by a file landing in an SFTP directory. The flow body does not change based on which trigger fired it; the difference shows up only in the source payload key.

A branch is a staging area for definition changes: edit safely, review the diff, promote to production. When git-backed storage is enabled, every change to a flow, environment, connection, or secret is committed automatically; a branch lets you stage a set of those changes off to the side and merge them only once you’ve reviewed them. It answers which version of the definitions runs — never which systems they talk to (that is the environment’s job).

Give a branch a feature-style name for the change it carries — edi-rework, add-nightly-reindex — not a tier name. URLs carry the branch as a path segment: /api/v1/main/flows/... runs the production version; /api/v1/edi-rework/flows/... runs the version staged on the edi-rework branch. Where git versioning is disabled, the alias live resolves to whatever the production branch is.

A branch is short-lived: it wants to be merged. It is not a place to keep a long-lived test system — a test system is a deployment target and belongs in an environment, not on a branch.

EntityYou write this when…Lives at
Flow…describing a pipeline: what runs, in what order, with what inputs and outputs.flows/{name}.flow.yaml
Connection…pointing at one external service: a database, an SFTP, an API.config/connections/{name}.connection.yaml
Environment…bundling connections into a runnable profile (dev, staging, prod).config/environments/{name}.environment.yaml
Secret…storing a credential a connection or flow needs at runtime.auth/secrets.enc (or HashiCorp Vault)