# Spec: Step Outputs ## Status Implemented. ## Scope This spec defines the step-level top-level `outputs` field, `DAGU_OUTPUT_FILE`, and output publication. The field shape is: ```yaml steps: - id: build outputs: - name: image_tag ``` It does not define the existing singular `output` field, `stdout.outputs`, `outputs.write`, or the `outputs` schema in `dagu-action.yaml`. Object-form `output`, `stdout.outputs`, `outputs.write`, and the `outputs` schema in `dagu-action.yaml` publish named outputs of their own, and Spec 007 defines how references read them. String-form `output: VAR` captures a variable rather than a named step output, so Spec 007 does not read it, and the rules below about failed attempts do not govern it: the variable is set from the attempt's stdout even when the step fails, which Spec 018 relies on for the aggregate of a `foreach` whose items partly failed. Value-resolution references to published outputs are defined by [Spec 007: Value Resolution Steps](007-value-resolution-steps.md). ## Goal Define a file-based way for a step to publish named values for later steps. The producing step writes records to `DAGU_OUTPUT_FILE`. Dagu parses that file after the step succeeds. Later steps read the values through value resolution. ## Input Input is a workflow YAML file accepted by the YAML schema spec. Step output validation extends: ```sh dagu validate ``` Workflow execution uses: ```sh dagu start ``` Rules: - Validation checks output declarations. - Validation must not execute steps. Example: ```yaml steps: - id: build run: | printf 'image_tag=v1.2.3\n' >> "$DAGU_OUTPUT_FILE" outputs: - name: image_tag ``` ## Output declarations `outputs` is an optional step field. Rules: - When present, `outputs` must be a non-empty sequence. - A step with `outputs` must define `id`. - Output names must be unique inside one step. - Unknown output item fields are invalid. - JSON Schema is not part of this spec. Output item fields: | Field | Required | Rules | | --- | --- | --- | | `name` | Yes | Must match `^[A-Za-z][A-Za-z0-9_]*$`. | | `type` | No | Must be `string` or `json` when present. Defaults to `string`. | ## Output reference inputs Value-resolution references to step outputs use the published output names from this spec. Rules: - Output names are scoped to the producing step. - Step outputs are scoped to one DAG document. - Inline sub-DAG documents have independent output scopes. - Reference syntax, escaping, dependency requirements, passive notices, and runtime lookup behavior are defined by [Spec 007: Value Resolution Steps](007-value-resolution-steps.md). - Unsupported `${...}` text outside Dagu-owned reference forms is preserved silently by [Spec 003: Value Resolution and Field Evaluation](003-value-resolution.md). ## Output file lifecycle For each step attempt, Dagu creates an empty output file before the executor starts. Rules: - Dagu exposes the output file path to the executor as `DAGU_OUTPUT_FILE`. - Executor specs define how each executor receives `DAGU_OUTPUT_FILE`. - Dagu must not read stdout, stderr, or logs as step outputs. - Dagu parses the output file only after the executor exits successfully. - If the executor fails, aborts, or times out, Dagu does not publish outputs from that attempt. - If output parsing fails, the attempt fails. - Normal retry behavior may retry the failed attempt. - Failed attempts publish no outputs. - Only the attempt that makes the step successful publishes outputs. - Each retry attempt receives a new empty output file. ## Output file format Dagu parses the output file as UTF-8 text. Invalid UTF-8 fails output parsing. Line endings are normalized to `\n` before parsing. Record formats: | Format | Syntax | Value | | --- | --- | --- | | Single-line | `name=value` | Text after the first `=`. The line ending is not part of the value. Empty values are valid. | | Multi-line | `name<> "$DAGU_OUTPUT_FILE" outputs: - name: image_tag - id: deploy depends: build env: IMAGE_TAG: ${steps.build.outputs.image_tag} run: ./deploy.sh "$IMAGE_TAG" ``` Valid JSON output: ```yaml steps: - id: inspect run: | cat >> "$DAGU_OUTPUT_FILE" <<'EOF' metadata<> "$DAGU_OUTPUT_FILE" outputs: - name: image_tag - id: deploy run: ./deploy.sh '${steps.build.outputs.image_tag}' ```