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:
[
{"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:
{
"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:
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.