arguments by the enclosing scope. This makes data flow visible in the workflow document itself and fully testable without running the engine.
The binding model
When the engine is about to dispatch a task, it resolves the task’s inputs by merging two sources:- The template’s
inputsdeclaration — the parameter schema (name, type, default). - The call-site
arguments— the values orvalueFromreferences provided by the enclosing DAG or Loop.
arguments[name].value— explicit value provided at the call site (non-empty, non-null).arguments[name].valueFrom— resolved from the evaluation environment (env).decls[name].value— static value declared on the template input itself.decls[name].valueFrom— template-declared default resolution.decls[name].default— fallback default.- (empty) — value is absent; the executor decides how to handle it.
arguments but not in the template’s inputs) are appended as-is, enabling callers to inject extra values without modifying the template.
Interpolation syntax
String fields inarguments and when expressions support {{key}} placeholder interpolation. The engine replaces each {{key}} with the corresponding value from the evaluation environment:
{{key}} token and the resolved value is a non-string type (e.g., an integer or array), the original Go value is preserved without string conversion. Mixed strings like "prefix-{{key}}-suffix" always produce a string via fmt.Sprint.
Keys not found in the evaluation environment are left as-is — the placeholder is not replaced, and no error is raised. Downstream validators or the executor are responsible for reporting missing required inputs.
The evaluation environment (EvalVars)
The binding engine builds a flatEvalVars map before resolving any parameter. The key space is:
Parameter types
Thetype field on a Parameter is a hint for validation and executor consumption:
Type enforcement is executor-specific; the engine itself does not reject mismatched types.
Input parameter declaration
Input parameters are declared on the template’sinputs.parameters list:
name: "outputs" has special meaning for the echo executor used in the playground (see The outputs special parameter below).
valueFrom: dynamic value resolution
valueFrom is the mechanism for wiring dynamic values between parts of a workflow:
- parameter
- expression
- secretKeyRef
- path
References a key in the EvalVars environment by name. This is the most common form:Supported reference formats for
parameter:workflow.arguments.parameters.<name>— workflow-level argument (legacy alias, normalized internally)workflow.parameters.<name>— canonical form of the aboveinputs.parameters.<name>— current scope’s resolved inputtasks.<name>.outputs.parameters.<param>— sibling task output
Output parameter declaration
Output parameters are declared on the template’soutputs.parameters list. For a Task template, the executor populates them at runtime. For a DAG or Loop template, valueFrom references lift values from child task outputs:
Parameter flow: a complete example
The following is from02-dag-linear.json — a three-task linear DAG where each task receives its inputs from the previous task’s outputs:
fetch-dataruns and producesbodyandcountas outputs.transformreads them viatasks.fetch.outputs.parameters.*in itsarguments.transform-dataproducessummary.notifyreadssummaryfromtasks.transform.outputs.parameters.summary.- The
mainDAG liftssummaryinto its own outputs for callers of this scope.
Workflow-level arguments
Workflow arguments declared inspec.arguments are available everywhere via the workflow.parameters.<name> key (or the legacy workflow.arguments.parameters.<name> alias):
The outputs special parameter
The playground’s echo executor reads a special input parameter named "outputs" to determine what it should emit. Its value is a JSON array of output parameter descriptors:
echo executor — a testing convenience that allows integration tests to mock any task output without implementing a real executor. Production executors declare their outputs through the ExecOutputs return value, not through input parameters.
Scoped access summary
To pass a value from an inner scope to an outer scope, declare it in the inner template’s
outputs and wire it through the parent node’s outputs.valueFrom.