Use Shell (shell.run) to run a multi-line script in the workflow runtime or on a remote SSH host. The same environment, standard input, structured input, files, and tenant secrets are delivered on every execution target.

Execution target

Choose Rollout to use the workflow's native, Docker, or Kubernetes runtime. Choose Remote (SSH) and an SSH Host connection to run on that host. A connectivity service such as Tailscale can carry SSH to a private network; only SSH connection failures (exit 255) are retried while that transport warms up. The remote script's own non-zero exit is never replayed by the transport.

Tenant secrets are resolved at step start on both targets, override plain environment values with the same name, and are registered for log redaction. Environment names must match ^[A-Za-z_][A-Za-z0-9_]*$.

Inputs

Input Type Description
env object Plain environment variables. Declared tenant secrets override matching keys
workdir string Working directory in the runtime, or the path on the SSH host
stdin string Bytes delivered to the script's standard input
input any JSON-encoded into the file named by $ROLLOUT_INPUT_FILE
files list Files materialized below workdir before the script starts

Each files entry has a relative path and exactly one source:

JSON
[
  {"path": "config/app.json", "content": "{\"enabled\":true}"},
  {"path": "assets/logo.png", "attachment_ref": {"id": "..."}}
]

Absolute paths, traversal (..), duplicate normalized paths, missing sources, and entries with both sources are rejected. Attachment references are resolved inside the current tenant. Docker and Kubernetes stage the payload under /rollout; SSH sends it as framed bytes on the command's single channel and extracts a tar archive below the remote workdir.

For Kubernetes, the rendered script, JSON input, stdin, files, and tenant secret values share one ephemeral Secret. Their combined payload must not exceed 1 MiB; an oversized step fails before pod creation with input_too_large. The script is mounted as /rollout/step.sh, so its size is not constrained by the container argv limit.

Outputs

Shell always returns stdout, stderr, and exit_code. capture_files collects selected workspace paths into the files output on runtimes with a shared workspace; it is unavailable for remote SSH paths.

Use Declared outputs to parse or project structured values. For example, a strict JSON stdout output is:

JSON
{
  "io": {
    "outputs": [
      {"id": "json", "source": "stdout", "parse": "json", "policy": "strict"}
    ]
  }
}

A declared output named warnings with policy warn also populates the run's warning channel. Warning strings are tenant-secret-redacted before the 50-item, 1 KiB-per-item display cap.

The removed capture_json and capture_lines switches are not accepted. Operators can inspect and migrate legacy stored graphs with:

SH
mix rollout.flows.migrate_capture_json
mix rollout.flows.migrate_capture_json --apply

The first command is a read-only affected-count report. --apply performs an idempotent tenant-atomic migration across workflows, releases, and branches.