Skip to content

Document Structure

A Workfile is a single YAML document with the following top-level keys.

workfile: 1 # optional; major format version this file targets
name: inbox_triage # optional, ^[a-z][a-z0-9_]*$
owner: support-team # optional, opaque
version: 7 # optional, opaque
on: { ... } # optional trigger declaration
inputs: { ... } # optional typed parameters
outputs: { ... } # optional result projection
recovery: { ... } # optional file-level recovery policy
steps: [ ... ] # required, unless `states` is present
initial: awaiting_approval # required with `states`
states: { ... } # alternative to `steps`

A file MUST contain exactly one of steps or states. A file that declares states MUST declare initial. A file that declares steps MUST NOT declare initial.

Implementations MUST reject an unknown top-level key. A key whose name begins with x- is not an unknown key.

name is optional. When it is absent, the deployment environment supplies the workflow’s identity. Implementations MUST record a name for every run.

owner and version are opaque. Neither is readable from an expression, and neither affects evaluation. version is an integer that an author increments when the definition changes. Implementations MUST record both values with every run. A deployment environment MAY use either value to select a definition.

workfile declares the major format version that the file targets. An implementation that does not support that version MUST reject the file. When workfile is absent, an implementation assumes its own highest supported major version. A resolved definition MUST record the version, whether or not the source declared it.

inputs declares the typed parameters that a caller supplies.

inputs:
priority_domains:
type: "list[string]"
default: []
required: false

Each entry is a field declaration, over the type system. Implementations MUST validate every input value before the run starts. An input that declares required: true and has no supplied value is a validation error. An absent optional input binds its default, or null when it declares none.

Inputs are readable as inputs.<name> in every scope.

outputs declares the workflow’s result. It is a projection, evaluated once after the last step completes.

outputs:
ticket_url: "{{ ticket.url }}"
category: "{{ classify.category }}"

Names MUST match ^[a-z][a-z0-9_]*$ and MUST be unique. The expressions are evaluated in the root scope and are subject to purity.

Implementations MUST evaluate outputs on any successful terminal outcome, including the outcome of a stop step. A reference to a step that did not run resolves to null, as a reference to a skipped step does. Implementations MUST NOT evaluate outputs when a run fails.

The projection is the run’s result. It is recorded, and a call step binds it. A file that declares no outputs produces an empty result, and a path into a call step on such a file is a validation error.

Every run exposes a run binding in the root scope:

Path Type Meaning
run.id string Unique per run. Identical on every replay.
run.started_at timestamp The instant the run started. Recorded once, and identical on every replay.

run.started_at is the only source of the current instant. A deadline or an offset derives from it with the time filters. There is no filter that reads a clock.