Document Structure
A Workfile is a single YAML document with the following top-level keys.
workfile: 1 # optional; major format version this file targetsname: inbox_triage # optional, ^[a-z][a-z0-9_]*$owner: support-team # optional, opaqueversion: 7 # optional, opaque
on: { ... } # optional trigger declarationinputs: { ... } # optional typed parametersoutputs: { ... } # optional result projectionrecovery: { ... } # optional file-level recovery policy
steps: [ ... ] # required, unless `states` is presentinitial: 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.
Identity
Section titled “Identity”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
Section titled “Inputs”inputs declares the typed parameters that a caller supplies.
inputs: priority_domains: type: "list[string]" default: [] required: falseEach 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
Section titled “Outputs”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.
Run metadata
Section titled “Run metadata”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.