Workfile Documents
A Workfile is one YAML document that describes one workflow. Its conformance is determined by the applicable serialization, document-structure, construct, trigger, capability, and profile requirements.
Document Structure
Section titled “Document Structure”A Workfile can contain the following top-level keys:
| Key | Required | Meaning |
|---|---|---|
workfile |
No | Explicit Workfile format discriminator. |
name |
No | Workflow name. |
owner |
No | Opaque owner metadata. |
version |
No | Opaque workflow revision metadata. |
on |
No | One or more trigger declarations. |
schemas |
No | Named object schemas. |
inputs |
No | Typed workflow inputs. |
outputs |
No | Declared workflow result. |
recovery |
No | File-level recovery policy defined by the Durable Execution Profile. |
steps |
One of | Root step list for a Core workflow. |
states |
One of | State definitions governed by the Stateful Workflow Profile. |
initial |
With states |
Initial state name. |
A Workfile MUST contain exactly one of steps and states. A Workfile with states MUST contain initial; one with steps MUST NOT contain initial.
The use of states activates the Stateful Workflow Profile. The use of recovery activates the Durable Execution Profile.
Duplicate keys and unknown top-level keys are governed by Serialization. Extension-prefixed keys are governed by Extensions and Forward Compatibility and do not alter workflow semantics unless their defining capability says otherwise.
Format Version
Section titled “Format Version”workfile, when present, is a positive integer selecting an explicitly versioned Workfile format. This revision defines format 1.
A document without workfile uses the versionless format defined by the selected Standard revision; in this revision, that format has the same syntax and meaning as format 1. An implementation MUST reject a Workfile whose declared format it does not support.
The meaning of an unversioned document MUST NOT depend on which other formats an implementation supports. Resolution MUST record the selected Standard revision and the declared format discriminator, if any.
Before 1.0.0, the selected exact Standard revision defines the versionless format and no compatibility with another minor revision is promised. Later revisions follow the compatibility rules under Obligations of the Standard.
Support for one explicitly versioned format does not imply support for another.
A validator that recognizes a format but lacks a feature required by an otherwise valid document MUST report the document as unsupported by that target, not invalid merely because of the missing implementation capability.
Identity and Metadata
Section titled “Identity and Metadata”name, when present, is a workflow name and MUST satisfy the name syntax below. It does not create an expression binding or change workflow evaluation.
An executor MAY assign a deployment-specific identity to a workflow. A stable workflow identity is REQUIRED when an applicable capability or profile uses identity across activations or runs.
The capability or profile defines its required scope and recording behavior. owner is an opaque string.
version is an opaque integer available to authors and deployments for identifying revisions. Neither value is an expression binding and neither changes evaluation.
A deployment MAY use them when selecting a workflow definition. A run MUST associate each declared name, owner, and version value with its logical execution state.
Every run has an immutable run binding in the root scope:
| Path | Type | Meaning |
|---|---|---|
run.id |
string |
Identifier unique to the run. |
run.started_at |
timestamp |
Recorded actual instant at which the run began, with display zone Z; for a delayed or catch-up schedule occurrence it is not the occurrence’s intended instant. |
run.dry_run |
bool |
Whether the deployment started the run with write effects suppressed. See Dry Runs. |
run.parent |
string? |
Calling run’s id, or null if no run called this one. |
The run members are recorded once and MUST NOT change during a run, recovery, or replay. The start instant is fixed; current-time observations follow Purity. A current-time action produces an ordinary nondeterministic action result, recorded wherever the applicable execution profile records action results.
Note: Every Core Executor supports the canonical time.now action to observe the current instant after the run begins, including after suspension when supported. Scheduled initiation remains independently claimable.
Inputs
Section titled “Inputs”inputs is a map from names to field declarations. A declaration is either a type-expression string or a map governed by Field Declarations.
A map declaration MUST contain exactly one of type and $ref. An input can declare required, default, description, and the other constraints permitted by that section. The restriction on combining required: true with default is defined under Field Declarations.
If an input is absent, its default is used. An optional input without a default follows the root-input row of Field Declarations.
Failure to supply a required input is an invocation.inputs rejection of the invocation or deployment operation that supplies the inputs. The same code applies to an undeclared input or a supplied or defaulted value that does not satisfy its declaration.
An invocation.inputs rejection occurs before a run starts and does not make the Workfile invalid or create a failed run. Before a run starts, the executor MUST validate every supplied or defaulted value against its declaration and MUST reject undeclared input names.
The resulting map is bound as inputs in the root scope and is visible from every nested scope. Input bindings are immutable.
Schemas
Section titled “Schemas”schemas is a map from names to object types expressed as JSON Schema draft 2020-12. Each entry is available only to $ref values in the same Workfile and is subject to Object Types and the Workfile Schema Dialect.
A reference to an absent schema is a validation error. A Workfile schema MUST NOT declare defined_by; tenant-defined extension points are connector-manifest declarations and cannot be introduced by a Workfile.
Declaring a schema does not itself create a binding or perform validation until a typed position refers to it.
Field Declarations
Section titled “Field Declarations”A field declaration is either a type-expression string or a map with exactly one of type and $ref. In a Workfile, $ref MUST resolve to a schema in that Workfile.
The map can additionally contain required, default, description, examples, and sensitive, and every constraint keyword that the Workfile schema dialect permits for the declared type. A constraint has the same meaning and parameter domain on a field declaration as on the equivalent schema node. A section that uses field declarations can further restrict these keys or define additional keys for that context.
required is boolean and defaults to false. default is a literal supplied when the field is absent. A declaration MUST NOT combine required: true with default.
The following table is the authoritative absence and null rule for field-declaration positions:
| Position | Absent optional, no default | Supplied T? evaluates to null |
Literal or statically null value |
|---|---|---|---|
Root workflow inputs |
Bind null. |
Supply null; the input binding exists. |
Supply null, valid only when the declared type admits it. |
State accepts |
Bind null. |
Supply null; the acceptance binding exists. |
Supply null, valid only when the declared type admits it. |
| Manifest fields, action arguments, declared object properties, and every other field-declaration position | Omit the member. | Omit the member; otherwise supply and validate the value as T. |
Supply null; runtime null alone does not imply omission. |
Required and defaulted fields do not permit conditional omission. A supplied null is distinct from absence and is valid only where the declared type admits null.
pattern is a regular expression under the Regular Expression Grammar and applies only to strings. The pattern constraint is satisfied when an unanchored search finds a match; \A and \z can require a whole-string match. maxLength and maxItems are nonnegative integers and apply only to strings and lists respectively.
examples is a list, and each example and any default MUST satisfy the declared type and every constraint. description and examples are informative and do not change validation.
sensitive is boolean and defaults to false. It is permitted on workflow inputs, state accepts, and every other position that admits an unrestricted field declaration.
A sensitive field is an ordinary typed value during execution, but an implementation MUST NOT display or export it and MUST apply the withholding requirements under Credentials and Sensitive Values to every retained representation. An implementation MUST retain a sensitive value for as long as an active run can require it for execution, durable continuation, or recovery.
The implementation MAY discard the sensitive value once no permitted continuation can read it and MUST replace it with a withheld marker in retained run data no later than the run’s terminal outcome. A record from which a required sensitive value has been discarded can be inspected or replayed using already recorded nondeterministic results, but MUST NOT be used to re-execute an operation that requires the value.
Sensitivity is structural: it applies to the declared field’s complete value. It does not imply transport encryption, access control, or secrecy of values derived from it; deployments remain responsible for those controls.
Outputs
Section titled “Outputs”outputs is a projection: a map from names to expression-bearing value structures. Its names become fields of the normal-completion result. In a step-form Workfile, the projection is evaluated in the root scope only on normal completion. The Stateful Workflow Profile defines the final-entry scope used for normal completion. The implicit dry-run state stop is the exception defined under Dry Runs; explicit wf.stop uses its own result projection.
Each output’s declared static type is inferred from its expression-bearing value structure under Static Typing and Assignability. An absent outputs contributes the empty object shape for normal completion. For state-form Workfiles, normal-completion inference first applies the final-entry scope rules.
The successful workflow result type MUST be the join of the normal-completion object shape and every statically declared wf.stop result shape in that Workfile. This includes stops in nested bodies and modifier-owned step lists, regardless of guards or reachability; stops in callees contribute only to their own workflow’s result type. Each stop projection is inferred in its own lexical scope, with an omitted result contributing the empty object shape. The existing object join rules give the union of keys, nullable types for missing keys, and joined types for shared keys. If a required join does not exist, validation MUST reject the Workfile with document.type.
Resolved validation of wf.call MUST infer this result transitively from the resolved callee; the call step has that object type, and paths beneath it are checked against the joined result’s names and inferred types. Output inference is part of the resolved workflow contract even though projections do not repeat explicit type declarations. The join affects static types only: a successful run returns the selected projection’s members without inserting keys from other projections. A permitted reference to a result member absent from that projection resolves to null.
The executor MUST NOT evaluate outputs after a failed run. It MUST NOT evaluate outputs after a cancelled run. A reference to a skipped, failed, or otherwise unexecuted step follows the binding rules for that outcome.
An evaluation fault while producing an output prevents a successful result and is handled as defined by Evaluation Faults. Normal completion without outputs produces an empty map. Call-result bindings and path validity are defined under wf.call. The successful workflow result and the values used to produce it are subject to the recording requirements of the applicable execution profile. Dry-run output substitution is defined under Dry Runs.
steps is an ordered list of zero or more steps. Step ordering is defined under Step Evaluation. Nested step lists use the same representation and ordering rule unless a construct expressly defines concurrent branches or another order.
The alternative top-level states form is not a step list. Its structure, initial state, transitions, and execution semantics are governed by Stateful Workflow Profile.
Names and Bindings
Section titled “Names and Bindings”Name Syntax and Reserved Names
Section titled “Name Syntax and Reserved Names”A binding position is a position whose name creates a binding or a named member of a scope or construct result during a run. The binding positions in this revision are step ids; trigger as names; output names; names in trigger or transition into projections and wf.render with projections; state input names; wf.for_each as names; wf.parallel branch names; state subscription names; template each block bindings; and inline or derived wf.render part names.
Every workflow-declared name MUST match the declared-name production in the Syntax Reference. Workflow-declared names comprise names in binding positions together with workflow names, input names, schema names, state names, and names in wf.call and wf.agent with projections.
A name in a binding position MUST NOT collide with a construct-created member visible in the same scope. A more specialized section can impose an additional restriction.
The names run, inputs, trigger, current, and error are reserved for bindings defined by this specification. A Workfile MUST NOT use a reserved name in a binding position.
Where a construct supplies the reserved error binding, its value is null when the scope has no failure and otherwise has the closed shape step: string, code: string, message: string, and details: json. message is implementation-defined text, and details is connector-supplied json, or null when no details are available.
The construct supplying error defines the scope relative to which step is expressed. Names MUST be unique within the map or scope that declares them.
The uniqueness requirement above makes two declarations that would create the same binding in one scope invalid. An inner scope MUST NOT shadow a binding visible from an enclosing scope.
Single Assignment
Section titled “Single Assignment”A binding associates one name with one value or scope for the life of a run. Bindings are created once and are never reassigned.
No Workfile syntax mutates a binding. A step id creates its step binding in the step’s enclosing scope.
Inputs, run metadata, trigger payloads, projections, construct-defined contextual values, and profile-defined state inputs create bindings only where their defining sections say so. Re-evaluation, retry, recovery, and replay MUST preserve the logical identity and single-assignment semantics of those bindings.
Scopes
Section titled “Scopes”The root scope contains run, inputs, trigger bindings when applicable, root projection bindings created by a trigger, and root step bindings. Scopes nest.
A step can reference bindings created earlier in its own scope and bindings visible from enclosing scopes. The nested-scope rules in the defining construct sections apply to wf.route branches, wf.choose arms, wf.for_each and wf.repeat iterations, and wf.parallel branches.
Profile-defined scopes are governed by their defining profile sections. A binding created in a nested scope is not directly visible outside it; the scope-creating step’s binding provides access to it.
Static validation MUST reject a reference to a binding that is not in scope or is declared only by a later step in the same sequential scope. Concurrent sibling scopes MUST NOT reference one another unless the defining construct expressly provides such a binding.
Step Paths
Section titled “Step Paths”A step path is the stable name of one logical step occurrence in a run and matches the step-path production in the Syntax Reference. A root step’s path is its id.
A nested step appends . and its id to the enclosing construct’s path. An iteration or state entry appends a zero-based index in brackets before the nested step id.
Examples include classify, triage.lead, poll[0].probe, and awaiting[2].remind. Auxiliary work uses parenthesized reserved segments allocated by the Reserved Step-Path Segment Registry.
An implementation MUST use step paths wherever a portable run history, trace, or replay input identifies a step occurrence. Presentation interfaces MAY display additional labels but MUST NOT change a standardized path stored in such an artifact.
Step Structure
Section titled “Step Structure”Reading a Step
Section titled “Reading a Step”A step is a map with exactly one entry. Its key is the step id and its value is the step body.
A step has no separate id field and is never anonymous. The body is REQUIRED.
The value under an operation key generally names its subject, with configuration beside it: wf.for_each takes a source, wf.parallel takes branches, and wf.repeat takes the repeated steps. wf.wait keeps an explicit for or until mode within its subject to distinguish an interval from a deadline. The defining sections specify the accepted shapes.
A validator MUST classify a body before applying operation-specific validation:
- A scalar or list is a compact
wf.valuebody. - A map with no operation key and no immediate standard step-modifier key is a compact
wf.valuebody over that map. - A map with no operation key and one or more immediate standard step-modifier keys is invalid.
- A map with exactly one operation key invokes that construct when the key is a
wf.key, independent of the value’s shape. - A map with exactly one operation key invokes that action when the key is an action operation key and its value is a map or
null. - A map with exactly one operation key is invalid with
document.structurewhen the key is an action operation key and its value is a scalar or list. - A map with more than one operation key is invalid.
For an invoked operation, each other key defined by that operation belongs to that operation; otherwise, a standard modifier permitted on that operation is a step modifier. A construct-specific key takes precedence over a same-named modifier, which is unavailable on that construct. An operation key contains a dot.
wf.<name> names a construct reserved to this specification. Any other operation key has the form connector.action and names an action resolved through a connector manifest.
Extension keys do not count as operation keys. Classification examines only the body’s immediate keys; dots in values or nested maps do not identify an operation.
A construct call MUST use its wf. name. An unprefixed construct name is an ordinary data key and does not affect classification.
An operation key used as data MUST be represented using explicit wf.value. The value under an action operation key MUST be an argument map or null; null denotes the empty argument map.
For a scalar or list under an action operation key, the document.structure diagnostic MUST explain that action arguments are a map or null and that explicit wf.value represents a dotted key used as data. Resolution of an action operation key over a map or null follows Resolution and Pinning. If resolution reports a missing connector or action member, the diagnostic MUST explain that explicit wf.value represents a dotted key used as data.
This classification cannot distinguish an intended data map from an action call when its sole dotted key resolves to an action and its map or null value satisfies that action’s input contract. Explicit wf.value is the unambiguous data form. A compact wf.value map MUST NOT have an immediate key whose name is a standard step modifier.
A data map with such a key MUST be represented using explicit wf.value. After classification, a validator MUST validate a construct against its defined keys and an action call against its resolved manifest, applying the manifest input contract defined under Actions.
The construct key tables define the accepted subject and configuration keys, their requiredness, domains, and defaults; a construct body additionally accepts only its permitted Step Modifiers and extension keys.
In those tables, subject is the value under the operation key, configuration is an adjacent construct key, and member is a key within the indicated nested map. “—” means no default; “absent” means no value is supplied. Evaluation scope, timing, and additional semantic constraints follow in the defining section. The tables for explicit wf.value do not describe its compact data forms.
An argument of static type T? for an optional, no-default field is omitted when it evaluates to null, as defined under Field Declarations. Every other argument that evaluates to null is supplied as null, not omitted.
Step Bindings
Section titled “Step Bindings”A step id always identifies the step for outcomes and step paths. The id creates a readable binding only when its body kind produces a value or scope:
| Body kind | Binding |
|---|---|
| Action call | Action’s declared output value. |
wf.value, wf.render, wf.agent, wf.call |
Construct’s produced value. |
wf.route, wf.choose |
Scope of the selected branch or arm. |
wf.for_each, wf.repeat |
Object containing summary members and the construct’s retained iteration scopes. |
wf.parallel |
Scope containing its named branch scopes. |
wf.wait_for |
Scope containing status, event, and bindings from its optional steps. See Durable Execution Profile. |
wf.wait, wf.stop, wf.fail |
No readable binding. |
The construct sections define the exact value and any profile activation. A path into a step kind with no readable binding is a validation error.
A step that is skipped, fails, or is not executed because control flow selected another path has the standardized outcome defined later. References permitted by static scope analysis resolve according to Binding Failed or Unexecuted Steps; absence of execution does not create a second assignment.
Step Modifiers
Section titled “Step Modifiers”A step modifier is a key adjacent to the operation key that changes execution policy without becoming an operation argument.
The modifiers defined by this specification and the body kinds on which they are permitted are:
| Modifier | Permitted body kinds | Defined under |
|---|---|---|
when |
Action calls, explicit wf.value, wf.render, wf.agent, wf.call, wf.route, wf.choose, wf.for_each, wf.parallel, wf.repeat, wf.wait, wf.wait_for, wf.stop, and wf.fail. when |
|
timeout |
Action calls, wf.agent, wf.call, wf.for_each, wf.parallel, and wf.repeat. Action Timeout Modifier, Composite-Construct Timeouts, wf.agent |
|
retry |
Action calls. retry |
|
idempotency_key |
Action calls. idempotency_key |
|
on_fail |
Action calls, wf.agent, wf.call, wf.route, wf.choose, wf.for_each, wf.parallel, wf.repeat, and wf.wait_for. Failure Policy Precedence |
|
on_unknown |
Action calls and wf.agent. on_unknown, wf.agent |
|
undo |
Action calls. | Compensation with undo |
reconcile |
Action calls. | Ambiguous Outcomes and on_unknown |
catch |
Action calls, wf.call, and wf.agent. |
catch |
connection |
Action calls. | Connection Selection |
recovery |
wf.route, wf.choose, wf.for_each, wf.parallel, and wf.repeat. Scope-Level Recovery |
The section defining a modifier supplies its syntax and semantics. A modifier is invalid on a body kind not listed.
Explicit wf.value accepts only when; compact wf.value accepts no modifiers.
A construct-specific key is not a modifier. Its permitted placement is governed by the construct that defines it.
An extension key is handled under Extensions and Forward Compatibility and MUST NOT be interpreted as a standard modifier.
Action Timeout Modifier
Section titled “Action Timeout Modifier”An action timeout accepts a nonnegative duration literal or an expression statically assignable to duration. It is evaluated once after when succeeds and before the first attempt and MUST produce a nonnegative duration; the resulting value bounds the wall-clock duration of every attempt, including retries.
If absent, the action has no Workfile-declared timeout, though a documented deployment limit can still apply. An action has no Workfile-declared bound on total step duration across attempts and retry delays; an enclosing composite timeout supplies such a bound.
Attempt results at expiry are defined under Action Timeouts; Composite-Construct Timeouts and wf.agent define the other timeout positions.
An action’s manifest can declare its default retry policy. The effective policy starts with the manifest policy when one is declared; otherwise it starts with attempts: 1, backoff: none, and honor_retry_after: false.
Each field present in the step’s retry map replaces the corresponding field in that policy. The effective policy has:
attempts, a positive integer counting the initial attempt;backoff, one ofnone,fixed, orexponential;initialandmaxdurations; andhonor_retry_after, defaulting to false.
Every retry-policy field is literal, in both manifests and step modifiers: attempts is a positive integer, backoff is none, fixed, or exponential, initial and max are nonnegative duration literals, and honor_retry_after is a boolean.
Expressions and interpolations are not permitted in a retry policy.
After merging, fixed and exponential require both initial and max, and honor_retry_after: true requires max; an incomplete effective policy is invalid with document.structure.
The resulting schedule and retry eligibility are defined under Effective Retry Policy.
idempotency_key
Section titled “idempotency_key”An action with idempotency: keyed requires the step modifier idempotency_key. The modifier’s expression MUST be statically assignable to non-null string; an enum[...] is accepted through ordinary assignability, while a nullable string is not.
The executor evaluates it once, supplies its string value as the input named by the manifest’s idempotency_input, and MUST reuse that value for every retry, recovery, or continuation of that logical step. The Workfile MUST NOT also supply that reserved input directly.
The key’s uniqueness domain is the resolved connection and action. Ordinary retry of a definitely retryable failure follows Effective Retry Policy for all declarations under Idempotency.
Reissue after an ambiguous result is governed by Core Ambiguity Disposition or Ambiguous Outcomes and on_unknown.
Connection Selection
Section titled “Connection Selection”These rules govern connector-backed action steps, top-level triggers, state subscriptions, and wf.wait_for; Deployment Connections defines connection contents and completeness.
Before execution or activation, resolution MUST select exactly one deployment connection for every connector-backed action, trigger, state subscription, and wf.wait_for.
When explicitly declared for any of those operations or trigger references, connection is always its sibling and is never a member of the operation’s argument or configuration map.
An explicit connection selector is a nonempty string literal and MUST NOT contain an interpolation. It names a deployment connection for the connector identified by the action or trigger reference.
When present, it selects that connection instead of any deployment default. When absent, deployment resolution MUST select an unambiguous default connection for that connector.
The selected connection MUST belong to the resolved connector and be compatible with its selected version, required fields, authentication, and scopes. A missing, ambiguous, incomplete, incompatible, or insufficiently scoped connection makes the resolved Workfile unsupported by that deployment with deployment.connection; it is not a validation error or runtime action failure.
Selection MUST be fixed before overlay-dependent validation and before execution or trigger activation and MUST NOT depend on a runtime value. The selected connection’s overlay, if any, governs static validation of every extension region the action or trigger consumes or produces.
Changing the selected connection or its overlay requires deployment validation and every affected overlay-dependent check to be performed again. Resolution MUST record the selected connection identity when a static type depends on the connection or its overlay.
An applicable history profile MUST record the selected connection identity for each operation attempt it retains. Connection fields and credentials are governed by Credentials and Sensitive Values.
Composite-Construct Timeouts
Section titled “Composite-Construct Timeouts”On wf.call, wf.for_each, wf.parallel, or wf.repeat, timeout accepts a nonnegative duration literal or an expression statically assignable to duration. It is evaluated once after the guard succeeds and before the construct body begins, and establishes a wall-clock deadline for the whole construct.
When the deadline is reached, the executor applies Internal Work Cancellation within the construct, after which the timed-out construct has a flow.timeout failure, creates no binding unless recovered by a handler, and is not cancelled. The construct’s own iteration or branch failure policy does not consume this failure; the construct’s catch, on_fail, and recovery policy and any enclosing construct’s iteration or branch failure policy apply under Failure Policy Precedence.
Child cancellation is governed by wf.call. The caller does not wait for cancellation to finish.
Any child result received after the calling step is cancelled is a late result. If a nested action was dispatched but has no definite result at the deadline, the enclosing deadline is its effective timeout and Action Timeouts determines whether the attempt definitely failed or is ambiguous.
The applicable ambiguity disposition takes precedence over completing the construct with flow.timeout; a possibly completed external effect MUST NOT be hidden by construct cancellation. Results from work ended by the deadline are governed by Late Results.
Triggers
Section titled “Triggers”on declares event sources that can initiate a run. Trigger syntax and static validation are part of Workfile Core.
Using a schedule, external-event, or polling trigger structurally requires the corresponding initiation capability; no separate capability declaration in the Workfile is required or permitted for that purpose.
Trigger Declarations
Section titled “Trigger Declarations”on is either one trigger-entry map or a nonempty list of trigger-entry maps. Each entry contains exactly one trigger operation key of the form connector.trigger.
The remaining permitted keys are consolidated here:
| Key | Required | Meaning |
|---|---|---|
<connector.trigger> |
Yes | Trigger operation and its configuration. |
as |
No | Payload binding name. |
into |
No | Root-binding projection for a multiple-trigger declaration. |
when |
No | Per-event guard. |
queue_by |
No | Queue partition expression. |
overlap |
No | Overlap policy. |
batch |
No | Batch policy. |
connection |
No | Deployment connection selector. |
x-* |
No | Extension key. |
A trigger-entry map is closed; every other key is invalid with document.structure. The trigger and its input contract MUST resolve from a connector manifest.
The value under the trigger operation key is its trigger configuration map, or null when it has no configuration. Trigger configurations are governed by the common rules below.
Trigger Configuration
Section titled “Trigger Configuration”A trigger configuration is a map validated against the resolved trigger manifest’s input declaration. A validator MUST reject unknown fields and MUST validate required fields, defaults, and types against that declaration.
An absent configuration is equivalent to an empty map and is valid only when the resulting configuration satisfies the manifest. The adjacent connection is governed by Connection Selection, including selection before overlay-dependent validation or activation.
The selected connection’s contents are governed by Credentials and Sensitive Values. A trigger-configuration value can contain expressions over root inputs only. Trigger configuration MUST NOT reference a trigger payload, a step binding, or a state binding. The implementation establishing the trigger source evaluates configuration at the time specified by the containing construct, validates the resulting values, and fixes them for the lifetime of that source or subscription.
For a top-level trigger, the initiation implementation evaluates the configuration when binding the trigger and fixes it for that deployment. A configuration evaluation fault prevents trigger activation; it does not create a failed run.
Stateful subscriptions and wf.wait_for incorporate this configuration contract and these expression restrictions through their defining profile sections.
Trigger Bindings and Deployment Inputs
Section titled “Trigger Bindings and Deployment Inputs”Each trigger manifest declares a default payload binding name. An entry’s optional as replaces that name.
The selected name binds the event payload in the root scope for a run started by that entry. A payload MUST satisfy the trigger’s declared payload type before the run starts.
A Workfile with on can start only from an invocation that selects exactly one entry and supplies that entry’s payload.
The executor MUST validate the supplied payload against the selected entry’s declared payload type before the run starts. A missing or invalid payload, an absent selected entry, or selection of more than one entry rejects the invocation with invocation.trigger; it does not create a failed run. A Workfile without on has no trigger binding, and a reference to it is invalid.
In a Workfile with on, trigger has a non-null closed object shape with name whose type is the enum of all selected payload binding names. trigger.name is the selected name and is non-null at runtime.
For example, an entry {as: ticket, support.opened: {}} makes trigger.name equal to "ticket", not "support.opened".
In a single-trigger declaration, the payload binding is statically non-nullable. In a multiple-trigger declaration, the selected entry’s payload binding is non-null at runtime and every other entry’s binding resolves to null; each entry-specific binding is therefore statically nullable. For multiple triggers, every entry MUST declare as, and the names MUST be distinct.
For a single trigger, the entry MUST declare as when the default name would collide with another root binding. A validator MUST NOT resolve a collision implicitly.
A trigger-started run has no caller, so its deployment supplies workflow inputs. Those values are validated exactly like caller-supplied inputs before trigger configuration is activated.
Deployment inputs are available to trigger configuration, guards, queue keys, partition expressions, and the run itself. They are deployment configuration, not catalog artifact content.
In a multiple-trigger declaration, an entry can declare into, a projection evaluated over that entry’s payload and inputs before the first step. If any entry declares into, every entry MUST do so, and all projections MUST create identical binding names and nested key structure.
The static type of each corresponding leaf is the join of that leaf’s types across all entries; the declaration is invalid if a join does not exist. Those names bind in the root scope from the selected entry’s projection and gain no additional nullability merely from invocation; an individual projected value remains nullable when its expression can evaluate to null under the ordinary rules.
A single-trigger declaration MUST NOT use into.
Trigger Guards
Section titled “Trigger Guards”when is an optional boolean expression evaluated once for each delivered event, before a run starts. It can reference only that entry’s payload binding and inputs.
If it is false, the event is suppressed and no run is created. A guard whose statically inferred type is incompatible with bool is invalid.
If static typing permits the expression and evaluation does not produce bool, or if evaluation otherwise faults, the event MUST NOT start a run. The implementation MUST distinguish that error from ordinary false suppression in any initiation record required by the active capability.
Queueing, Overlap, and Batching
Section titled “Queueing, Overlap, and Batching”queue_by is an expression over the payload binding and inputs. Its static type MUST be a non-null scalar type. For a batched trigger, queue_by sees the list-valued payload binding defined below.
Without batch, it is evaluated once per event; with batch, it is evaluated once per closed batch. It MUST produce a non-null scalar value. Equal keys identify one queue for the same workflow identity. Without batch, events in that queue are ordered by receipt. With batch, closed batches in that queue are ordered by closure. At most one associated run executes at a time.
Different keys establish no relative order. A run retains its key until it reaches a terminal outcome.
overlap, when present, MUST be the literal skip; no other value is defined. overlap: skip suppresses an event that would start while an applicable run is in flight.
With queue_by, only a run holding an equal key is applicable; without it, any in-flight run of the same workflow identity is applicable. Suspension does not end the in-flight interval.
batch is a map whose optional fields are size, max_wait, and partition_by. A batch declaration MUST contain at least one of size and max_wait.
size is a positive integer. max_wait is a nonnegative duration literal.
partition_by is evaluated once per event over that event’s payload and inputs; one batch MUST NOT mix unequal partition values. when is also evaluated per individual event.
In the run, the trigger payload binding contains the ordered list of accepted events in the batch and has static type list[P], where P is the manifest payload type. The entry’s into projection sees that list and is evaluated once after the batch closes. batch MUST NOT appear with overlap.
Without queue_by, the Standard establishes no ordering between batches unless the activated initiation capability expressly does so. Syntax and static requirements in this subsection are base requirements; event retention, timing, delivery, and execution behavior are requirements of the trigger’s activated initiation capability.
Multiple Triggers
Section titled “Multiple Triggers”Exactly one trigger entry initiates a particular run. Its payload binding contains the delivered payload.
Every other entry’s payload binding resolves to null for that run. trigger.name identifies the entry that fired.
All entries are independently resolved and validated, and each structurally activates the capability required by its trigger kind. An initiation implementation MUST establish support for every capability required by the declaration before it activates the workflow and MUST NOT silently ignore an unsupported entry.
Bindings created by matching into projections provide the portable common input shape across entries. Without into, steps can inspect trigger.name or the nullable entry bindings to select entry-specific behavior.
Queue keys from different entries share a queue when their evaluated values are equal and the workflow identity is the same.