Task Reference
Task YAML schema
Every top-level key of a task definition, with types, per-key examples, the error_handling sub-schema, and validation errors.
Task YAML schema
This schema governs task files — the YAML pipelines stored in tasks/ or in the tasks table. src/task-parser.ts parses a task into a TaskDefinition, and src/task-validator.ts checks it statically before any run. Connector credentials never appear in task YAML: a task declares typed connector slots, and actual configurations are injected at runtime.
Top-level keys
| Key | Type | Required | Description |
|---|---|---|---|
name |
string | No | Task name. Defaults to the file name without its extension. |
description |
string | No | Human-readable description. |
output |
string | No | Output format: ndjson (default), json, or none. |
lookup_connector |
string | No | Connector slot backing lookup steps and the $callMethod / $getDestinationId JSONata helpers. |
masking |
object | No | PII masking toggle: enabled and optional seed. |
cursor_store |
string | No | Connector slot used to persist step cursors. |
arguments |
object | No | Typed runtime parameters, keyed by name. |
connectors |
object | No | Connector slots, keyed by name, each with a type. |
variables |
object | No | Typed constants, keyed by name, each with type and value. |
metrics |
array | No | Metrics backend configurations (backend + optional config). |
steps |
array | Yes | Pipeline steps, executed as a single linear stream. |
loop |
object | No | Repeats the main pipeline in one run. |
Any other top-level key produces the validation warning Unknown top-level key: '<key>'.
output
Controls what happens to items that reach the end of the pipeline:
ndjson(default) — each item is written as one JSON line to stdout.json— all items are collected and written as a single JSON array to stdout.none— no stdout output; use when the last step writes to a Connector.
output is a top-level key only. There is no per-step output control — putting output (or quiet, silent, and similar keys) on a step raises a validation warning.
connectors
Each slot declares a name and a type — nothing more. Actual configuration is injected at runtime from connectors.yaml (CLI) or the connectors table (server), so tasks stay portable.
connectors:
source:
type: csv
destination:
type: sqliteInline config under a slot is flagged: Connector '<name>' has inline config — connectors should declare type only; config is injected at runtime. A slot no step references produces the warning Connector '<name>' is defined but never referenced by any step.
arguments
Runtime parameters supplied when a run starts — from a Job Template task node, CLI --arguments, the server API, or a UI form. Each argument declares:
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | string, number, boolean, string[], or number[]. |
description |
string | No | Help text shown to operators. |
required |
boolean | No | Reject the run when the value is missing. |
default |
any | No | Value used when the argument is omitted. |
enum |
array | No | Allowed values; anything else is rejected. |
arguments:
account_id:
type: string
required: true
description: Integrated account to pull from
batch_limit:
type: number
default: 100At run start every provided value is coerced to its declared type, so arguments.<name> inside JSONata is always the declared type. Missing required arguments fail with Argument "<name>" is required but was not provided; values outside enum fail with Argument "<name>" must be one of [...] but got <value>. Arguments also accept UI widget fields — see Arguments schema.
variables
Typed constants defined inside the task, read in JSONata as variables.<name>. Each entry must have type and value; description is optional.
variables:
target_status:
type: string
value: active
description: Status to filter by
batch_size:
type: number
value: 100Valid types match argument types: string, number, boolean, string[], number[]. A variable never referenced in any expression produces a validation warning.
steps
An array of step objects. Only these keys are valid on a step — anything else raises Unknown step key: '<key>':
| Key | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique within the task; read downstream as steps.<name>.output. |
type |
string | Yes | A registered step type — see Steps overview. |
config |
object or string | Depends on type | Static YAML object, or a JSONata expression string evaluated per item. |
run_if |
string | No | JSONata condition; the step runs only when truthy. When falsy, the item passes through unchanged. |
skip_if |
string | No | JSONata condition; the step is skipped when truthy. The item passes through unchanged. |
error_handling |
string | No | ignore, ignore_rest, or fail (default). See below. |
concurrency |
number | No | Max concurrent executions for this step. Defaults to 1 (sequential). Upstream pauses with backpressure at the limit. |
batch |
number or string | No | Collect output into arrays of this size before emitting downstream. A JSONata expression string is resolved on the first item. The final batch may be smaller. |
spool |
boolean or string | No | Collect all output into a single array, emitted once when the stream ends. A JSONata expression string is resolved on the first item. |
debug |
boolean | No | Print this step's input, config, and output to stderr. |
cursor |
object | No | Cursor persistence for the step: an object with a key string, stored via the cursor_store connector. |
steps:
- name: read_users
type: call_method
config:
connector: source
method: read
args:
resource: users
- name: upsert_user
type: call_method
concurrency: 5
error_handling: ignore
config: |
{
"connector": "destination",
"method": "upsert",
"args": { "table": "users", "data": input, "conflict_columns": ["id"] }
}A string config is compiled as JSONata and evaluated per item with { input, arguments, steps, variables, job_config }. An object config is passed verbatim and never evaluated — a JSONata reference such as arguments.x inside a static object is a bug the validator flags. Step-specific config keys are documented on each step's page; see Steps overview.
error_handling
Controls what happens when a step throws for an item:
| Value | Behavior |
|---|---|
fail (default) |
The error stops the entire task. |
ignore |
Logs a warning and emits an empty item so downstream steps still run for it. |
ignore_rest |
Logs a warning and emits nothing — remaining steps are skipped for this item, but the task continues with other items. |
Any other value fails validation with Invalid error_handling: '<value>' (must be ignore, ignore_rest, or fail). For retry patterns and when to choose each policy, see Error handling, retries, and loops.
loop
Repeats the main pipeline within a single run — for polling, delta sync, or drain-until-empty workloads.
loop:
sleep_ms: 30000
max_iterations: 100
max_duration_ms: 3600000
until_empty:
from_step: read_users| Key | Type | Required | Description |
|---|---|---|---|
sleep_ms |
integer | Yes | Milliseconds to sleep between iterations. Must be >= 10000. |
check_num_times |
integer | No | Consecutive falsy checks tolerated before exiting. Must be >= 1 and requires loop.steps or loop.until_empty. |
max_iterations |
integer | No | Safety cap on main pipeline runs. |
max_duration_ms |
integer | No | Wall-clock limit from task start. Must be >= 10000. |
steps |
array | No | Continuation-check steps run after each drain; the final step's output is coerced to a boolean. |
until_empty |
object | No | { from_step: "<step name>" } — re-run the main pipeline while that step still returns rows. |
Loop steps accept the same keys as main steps except cursor. Ending loop.steps with a call_method step produces a warning, because its output is coerced to a boolean ambiguously — prefer ending with a transform.
masking
Toggles deterministic PII masking for $mask bindings in JSONata:
masking:
enabled: ${MASK_PII}
seed: ${MASK_SEED}enabled is coerced to a boolean (true, 1, yes, on count as true). Environment variables in this block resolve leniently: an unset variable becomes an empty string, so masking is simply off where the toggle is not defined. Keys other than enabled and seed produce the warning Unknown key '<key>' in masking block.
metrics
An array of metrics backend configurations. Each entry must have a backend string and may carry a backend-specific config object; environment variables inside config are resolved at parse time.
metrics:
- backend: statsd
config:
host: ${STATSD_HOST}Available backends and their config keys are documented in Metrics config.
Validation errors
Static validation (envoy validate and the server's validate endpoint) emits these messages verbatim. Errors block the run; warnings do not.
Task must have a steps array — the top-level steps key is missing or not a list. Add at least one step under steps:.
Task must have at least one step — steps is an empty array. A pipeline needs a source step.
Invalid output format: '<value>' (must be ndjson, json, or none) — output is set to something else. Use one of the three formats.
Connector '<name>' must have a type — a connector slot is missing its type. Every slot needs exactly one type string.
Unknown connector type: '<type>'. Available: <list> — the slot's type is not a registered connector. Pick a type from the listed registry.
Unknown step type: '<type>' — the step's type is not one of the 15 registered types. Check spelling against Steps overview.
Duplicate step name: '<name>' — two steps share a name. Names must be unique because downstream expressions address them as steps.<name>.output.
Transform step config must be a JSONata expression string — a transform step has an object config. Use a config: | block string.
Invalid JSONata expression: <message> — a string config, run_if, or skip_if fails to compile. Fix the expression; the message includes the JSONata error code and token.
Connector '<name>' not defined in task — a step's config references a connector slot that is not declared under connectors. Declare the slot or fix the name.
Method '<method>' is not available on <type> connector. Available: <list> — a call_method step names a method the connector type does not expose. Use one of the listed methods.
concurrency must be a positive integer — concurrency is zero, negative, or not an integer.
batch must be a positive integer or JSONata expression — batch is neither a positive integer nor an expression string.
spool must be a boolean or JSONata expression — spool is neither a boolean nor an expression string.
loop.sleep_ms must be >= 10000 (minimum 10 seconds between iterations) — the loop sleep is under 10 seconds. Raise it to avoid tight loops.
loop.check_num_times requires loop.steps or loop.until_empty — a check count is set without anything to check. Add continuation steps or an until_empty block.
loop.until_empty references unknown step '<name>' — from_step does not match any main step name.
cursor_store references undefined connector '<name>' — the cursor_store slot is not declared under connectors. The same applies to lookup_connector (lookup_connector references undefined connector '<name>').
Static config contains a JSONata reference ('<leaf>'). Static object configs are passed verbatim and never evaluated — convert this step's config to a JSONata string (config: |). — an object config embeds input.x, arguments.x, variables.x, or steps.x. Change the config to a JSONata string so the reference is evaluated.
Related
- Steps overview — all 15 step types and how to choose one
- JSONata reference — expression contexts and helper functions
- Task anatomy and authoring workflow — how to build and test a task
- Error handling, retries, and loops — the guide behind
error_handling,loop, andmasking